From 1e5a47397a1a8572a430c20a6d12bb73bee4e430 Mon Sep 17 00:00:00 2001 From: Bryanskiy Date: Tue, 18 Jun 2024 14:04:28 +0300 Subject: [PATCH] Delegation: support coercion for target expression --- compiler/rustc_ast_lowering/src/delegation.rs | 191 +++++++++++------- compiler/rustc_hir_typeck/src/method/probe.rs | 46 +++++ compiler/rustc_middle/src/hir/map/mod.rs | 15 ++ compiler/rustc_middle/src/ty/mod.rs | 4 +- compiler/rustc_resolve/src/late.rs | 8 +- compiler/rustc_resolve/src/lib.rs | 3 + tests/ui/delegation/bad-resolve.rs | 3 + tests/ui/delegation/bad-resolve.stderr | 24 ++- tests/ui/delegation/explicit-paths-pass.rs | 4 +- tests/ui/delegation/explicit-paths.rs | 4 +- tests/ui/delegation/explicit-paths.stderr | 8 +- tests/ui/delegation/glob-glob.rs | 6 +- tests/ui/delegation/method-call-priority.rs | 32 +++ tests/ui/delegation/self-coercion.rs | 26 +++ tests/ui/delegation/target-expr.rs | 6 +- tests/ui/delegation/target-expr.stderr | 35 +++- 16 files changed, 313 insertions(+), 102 deletions(-) create mode 100644 tests/ui/delegation/method-call-priority.rs create mode 100644 tests/ui/delegation/self-coercion.rs diff --git a/compiler/rustc_ast_lowering/src/delegation.rs b/compiler/rustc_ast_lowering/src/delegation.rs index d9dd0b3bca534..872f9289d0f3d 100644 --- a/compiler/rustc_ast_lowering/src/delegation.rs +++ b/compiler/rustc_ast_lowering/src/delegation.rs @@ -38,7 +38,7 @@ use crate::{ImplTraitPosition, ResolverAstLoweringExt}; -use super::{ImplTraitContext, LoweringContext, ParamMode}; +use super::{ImplTraitContext, LoweringContext, ParamMode, ParenthesizedGenericArgs}; use ast::visit::Visitor; use hir::def::{DefKind, PartialRes, Res}; @@ -66,17 +66,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let Ok(sig_id) = sig_id else { return false; }; - if let Some(local_sig_id) = sig_id.as_local() { - // The value may be missing due to recursive delegation. - // Error will be emmited later during HIR ty lowering. - self.resolver.delegation_fn_sigs.get(&local_sig_id).map_or(false, |sig| sig.has_self) - } else { - match self.tcx.def_kind(sig_id) { - DefKind::Fn => false, - DefKind::AssocFn => self.tcx.associated_item(sig_id).fn_has_self_parameter, - _ => span_bug!(span, "unexpected DefKind for delegation item"), - } - } + self.has_self(sig_id, span) } pub(crate) fn lower_delegation( @@ -107,12 +97,29 @@ impl<'hir> LoweringContext<'_, 'hir> { span: Span, ) -> Result { let sig_id = if self.is_in_trait_impl { item_id } else { path_id }; - let sig_id = - self.resolver.get_partial_res(sig_id).and_then(|r| r.expect_full_res().opt_def_id()); - sig_id.ok_or_else(|| { - self.tcx - .dcx() - .span_delayed_bug(span, "LoweringContext: couldn't resolve delegation item") + self.get_resolution_id(sig_id, span) + } + + fn has_self(&self, def_id: DefId, span: Span) -> bool { + if let Some(local_sig_id) = def_id.as_local() { + self.resolver.delegation_fn_sigs.get(&local_sig_id).map_or(false, |sig| sig.has_self) + } else { + match self.tcx.def_kind(def_id) { + DefKind::Fn => false, + DefKind::AssocFn => self.tcx.associated_item(def_id).fn_has_self_parameter, + _ => span_bug!(span, "unexpected DefKind for delegation item"), + } + } + } + + fn get_resolution_id(&self, node_id: NodeId, span: Span) -> Result { + let def_id = + self.resolver.get_partial_res(node_id).and_then(|r| r.expect_full_res().opt_def_id()); + def_id.ok_or_else(|| { + self.tcx.dcx().span_delayed_bug( + span, + format!("LoweringContext: couldn't resolve node {:?} in delegation item", node_id), + ) }) } @@ -122,7 +129,7 @@ impl<'hir> LoweringContext<'_, 'hir> { predicates: &[], has_where_clause_predicates: false, where_clause_span: span, - span: span, + span, }) } @@ -222,12 +229,7 @@ impl<'hir> LoweringContext<'_, 'hir> { })); let path = self.arena.alloc(hir::Path { span, res: Res::Local(param_id), segments }); - - hir::Expr { - hir_id: self.next_id(), - kind: hir::ExprKind::Path(hir::QPath::Resolved(None, path)), - span, - } + self.mk_expr(hir::ExprKind::Path(hir::QPath::Resolved(None, path)), span) } fn lower_delegation_body( @@ -236,25 +238,18 @@ impl<'hir> LoweringContext<'_, 'hir> { param_count: usize, span: Span, ) -> BodyId { - let path = self.lower_qpath( - delegation.id, - &delegation.qself, - &delegation.path, - ParamMode::Optional, - ImplTraitContext::Disallowed(ImplTraitPosition::Path), - None, - ); let block = delegation.body.as_deref(); self.lower_body(|this| { - let mut parameters: Vec> = Vec::new(); - let mut args: Vec> = Vec::new(); + let mut parameters: Vec> = Vec::with_capacity(param_count); + let mut args: Vec> = Vec::with_capacity(param_count); + let mut target_expr = None; for idx in 0..param_count { let (param, pat_node_id) = this.generate_param(span); parameters.push(param); - let arg = if let Some(block) = block + if let Some(block) = block && idx == 0 { let mut self_resolver = SelfResolver { @@ -263,56 +258,103 @@ impl<'hir> LoweringContext<'_, 'hir> { self_param_id: pat_node_id, }; self_resolver.visit_block(block); - let block = this.lower_block(block, false); - hir::Expr { - hir_id: this.next_id(), - kind: hir::ExprKind::Block(block, None), - span: block.span, - } + target_expr = Some(this.lower_block_noalloc(block, false)); } else { let pat_hir_id = this.lower_node_id(pat_node_id); - this.generate_arg(pat_hir_id, span) + let arg = this.generate_arg(pat_hir_id, span); + args.push(arg); }; - args.push(arg); } - let args = self.arena.alloc_from_iter(args); - let final_expr = this.generate_call(path, args); + let final_expr = this.finalize_body_lowering(delegation, target_expr, args, span); (this.arena.alloc_from_iter(parameters), final_expr) }) } - fn generate_call( + // Generates expression for the resulting body. If possible, `MethodCall` is used + // instead of fully qualified call for the self type coercion. See `consider_candidates` + // for more information. + fn finalize_body_lowering( &mut self, - path: hir::QPath<'hir>, - args: &'hir [hir::Expr<'hir>], + delegation: &Delegation, + target_expr: Option>, + mut args: Vec>, + span: Span, ) -> hir::Expr<'hir> { - let callee = self.arena.alloc(hir::Expr { - hir_id: self.next_id(), - kind: hir::ExprKind::Path(path), - span: path.span(), - }); + let (stmts, call, block_id) = if self + .get_resolution_id(delegation.id, span) + .and_then(|def_id| Ok(self.has_self(def_id, span))) + .unwrap_or_default() + && delegation.qself.is_none() + { + let ast_segment = delegation.path.segments.last().unwrap(); + let segment = self.lower_path_segment( + delegation.path.span, + ast_segment, + ParamMode::Optional, + ParenthesizedGenericArgs::Err, + ImplTraitContext::Disallowed(ImplTraitPosition::Path), + None, + None, + ); + let segment = self.arena.alloc(segment); + + let args = &*self.arena.alloc_from_iter(args); + let (stmts, receiver, args, block_id) = if let Some(target_expr) = target_expr { + // Use unit type as a receiver if no expression is provided. + let receiver = target_expr.expr.unwrap_or_else(|| { + self.arena.alloc(self.mk_expr(hir::ExprKind::Tup(&[]), span)) + }); + (target_expr.stmts, receiver, args, target_expr.hir_id) + } else { + (&*self.arena.alloc_from_iter([]), &args[0], &args[1..], self.next_id()) + }; - let expr = self.arena.alloc(hir::Expr { - hir_id: self.next_id(), - kind: hir::ExprKind::Call(callee, args), - span: path.span(), - }); + let method_call_id = self.next_id(); + if let Some(traits) = self.resolver.delegation_trait_map.remove(&delegation.id) { + self.trait_map.insert(method_call_id.local_id, traits.into_boxed_slice()); + } + + let method_call = self.arena.alloc(hir::Expr { + hir_id: method_call_id, + kind: hir::ExprKind::MethodCall(segment, receiver, args, span), + span, + }); + + (stmts, method_call, block_id) + } else { + let path = self.lower_qpath( + delegation.id, + &delegation.qself, + &delegation.path, + ParamMode::Optional, + ImplTraitContext::Disallowed(ImplTraitPosition::Path), + None, + ); + + if let Some(target_expr) = target_expr { + let target_expr = self.arena.alloc(target_expr); + let fst_arg = + self.mk_expr(hir::ExprKind::Block(target_expr, None), target_expr.span); + args.insert(0, fst_arg); + } + let args = self.arena.alloc_from_iter(args); + let callee_path = self.arena.alloc(self.mk_expr(hir::ExprKind::Path(path), span)); + + let call = self.arena.alloc(self.mk_expr(hir::ExprKind::Call(callee_path, args), span)); + + (&*self.arena.alloc_from_iter([]), call, self.next_id()) + }; let block = self.arena.alloc(hir::Block { - stmts: &[], - expr: Some(expr), - hir_id: self.next_id(), + stmts, + expr: Some(call), + hir_id: block_id, rules: hir::BlockCheckMode::DefaultBlock, - span: path.span(), + span, targeted_by_break: false, }); - - hir::Expr { - hir_id: self.next_id(), - kind: hir::ExprKind::Block(block, None), - span: path.span(), - } + self.mk_expr(hir::ExprKind::Block(block, None), span) } fn generate_delegation_error( @@ -333,11 +375,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let header = self.generate_header_error(); let sig = hir::FnSig { decl, header, span }; - let body_id = self.lower_body(|this| { - let expr = - hir::Expr { hir_id: this.next_id(), kind: hir::ExprKind::Err(err), span: span }; - (&[], expr) - }); + let body_id = self.lower_body(|this| (&[], this.mk_expr(hir::ExprKind::Err(err), span))); DelegationResults { generics, body_id, sig } } @@ -349,6 +387,11 @@ impl<'hir> LoweringContext<'_, 'hir> { abi: abi::Abi::Rust, } } + + #[inline] + fn mk_expr(&mut self, kind: hir::ExprKind<'hir>, span: Span) -> hir::Expr<'hir> { + hir::Expr { hir_id: self.next_id(), kind, span } + } } struct SelfResolver<'a> { diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs index 3986374a343f0..37b2ecb1a9f02 100644 --- a/compiler/rustc_hir_typeck/src/method/probe.rs +++ b/compiler/rustc_hir_typeck/src/method/probe.rs @@ -1218,8 +1218,54 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { )>, mut unstable_candidates: Option<&mut Vec<(Candidate<'tcx>, Symbol)>>, ) -> Option> { + // Delegation item can be expanded into method calls or fully qualified calls + // depending on the callee's signature. Method calls are used to allow + // autoref/autoderef for target expression. For example in: + // + // trait Trait : Sized { + // fn by_value(self) -> i32 { 1 } + // fn by_mut_ref(&mut self) -> i32 { 2 } + // fn by_ref(&self) -> i32 { 3 } + // } + // + // struct NewType(SomeType); + // impl Trait for NewType { + // reuse Trait::* { self.0 } + // } + // + // `self.0` will automatically coerce. The difference with existing method lookup + // is that methods in delegation items are pre-resolved by callee path (`Trait::*`). + // Therefore, we are only forced to consider the pre-resolved method here. + let delegation_res = if self.fcx.tcx.hir().opt_delegation_sig_id(self.body_id).is_some() { + let body = self.tcx.hir().body_owned_by(self.body_id); + let block = match body.value.kind { + hir::ExprKind::Block(block, _) => block, + _ => unreachable!(), + }; + let expr = block.expr.unwrap(); + let res_id = match expr.kind { + hir::ExprKind::MethodCall(segment, ..) => segment.res.def_id(), + hir::ExprKind::Call( + hir::Expr { kind: hir::ExprKind::Path(hir::QPath::Resolved(_, path)), .. }, + _, + ) => path.res.def_id(), + _ => unreachable!(), + }; + Some((expr.hir_id, res_id)) + } else { + None + }; let mut applicable_candidates: Vec<_> = candidates .iter() + .filter(|candidate| { + if let Some((expr_id, res_id)) = delegation_res + && self.scope_expr_id == expr_id + && candidate.item.def_id != res_id + { + return false; + } + true + }) .map(|probe| { (probe, self.consider_probe(self_ty, probe, possibly_unsatisfied_predicates)) }) diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs index 305ba1ef3bbc8..c7161885214ee 100644 --- a/compiler/rustc_middle/src/hir/map/mod.rs +++ b/compiler/rustc_middle/src/hir/map/mod.rs @@ -728,6 +728,21 @@ impl<'hir> Map<'hir> { } } + pub fn opt_delegation_sig_id(self, def_id: LocalDefId) -> Option { + if let Some(ret) = self.get_fn_output(def_id) + && let FnRetTy::Return(ty) = ret + && let TyKind::InferDelegation(sig_id, _) = ty.kind + { + return Some(sig_id); + } + None + } + + #[inline] + pub fn delegation_sig_id(self, def_id: LocalDefId) -> DefId { + self.opt_delegation_sig_id(def_id).unwrap() + } + #[inline] fn opt_ident(self, id: HirId) -> Option { match self.tcx.hir_node(id) { diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 9c2bfc12a18a1..aa44ca41c2b29 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -224,8 +224,10 @@ pub struct ResolverAstLowering { /// Lints that were emitted by the resolver and early lints. pub lint_buffer: Steal, - /// Information about functions signatures for delegation items expansion + /// Information about functions signatures for delegation items expansion. pub delegation_fn_sigs: LocalDefIdMap, + /// Separate `trait_map` for delegation items only. + pub delegation_trait_map: NodeMap>, } #[derive(Debug)] diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 5ab6ba23a7da6..c50994d5a1c5b 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -3315,15 +3315,19 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { if let Some(qself) = &delegation.qself { self.visit_ty(&qself.ty); } + let last_segment = delegation.path.segments.last().unwrap(); + let traits = self.traits_in_scope(last_segment.ident, ValueNS); + // Saving traits for a `MethodCall` that has not yet been generated. + self.r.delegation_trait_map.insert(delegation.id, traits); + self.visit_path(&delegation.path, delegation.id); if let Some(body) = &delegation.body { self.with_rib(ValueNS, RibKind::FnOrCoroutine, |this| { // `PatBoundCtx` is not necessary in this context let mut bindings = smallvec![(PatBoundCtx::Product, Default::default())]; - let span = delegation.path.segments.last().unwrap().ident.span; this.fresh_binding( - Ident::new(kw::SelfLower, span), + Ident::new(kw::SelfLower, last_segment.ident.span), delegation.id, PatternSource::FnParam, &mut bindings, diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 3a831a7f19e06..78a3a76a2f8fd 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -1146,6 +1146,7 @@ pub struct Resolver<'a, 'tcx> { /// Amount of lifetime parameters for each item in the crate. item_generics_num_lifetimes: FxHashMap, delegation_fn_sigs: LocalDefIdMap, + delegation_trait_map: NodeMap>, main_def: Option, trait_impls: FxIndexMap>, @@ -1513,6 +1514,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { doc_link_traits_in_scope: Default::default(), all_macro_rules: Default::default(), delegation_fn_sigs: Default::default(), + delegation_trait_map: NodeMap::default(), glob_delegation_invoc_ids: Default::default(), impl_unexpanded_invocations: Default::default(), impl_binding_keys: Default::default(), @@ -1629,6 +1631,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { lifetime_elision_allowed: self.lifetime_elision_allowed, lint_buffer: Steal::new(self.lint_buffer), delegation_fn_sigs: self.delegation_fn_sigs, + delegation_trait_map: self.delegation_trait_map, }; ResolverOutputs { global_ctxt, ast_lowering } } diff --git a/tests/ui/delegation/bad-resolve.rs b/tests/ui/delegation/bad-resolve.rs index f378e05304b29..f15e6aa81afb0 100644 --- a/tests/ui/delegation/bad-resolve.rs +++ b/tests/ui/delegation/bad-resolve.rs @@ -34,6 +34,9 @@ impl Trait for S { reuse foo { &self.0 } //~^ ERROR cannot find function `foo` in this scope + reuse Trait::foo2 { self.0 } + //~^ ERROR cannot find function `foo2` in trait `Trait` + //~| ERROR method `foo2` is not a member of trait `Trait` } mod prefix {} diff --git a/tests/ui/delegation/bad-resolve.stderr b/tests/ui/delegation/bad-resolve.stderr index 883ff523bcfea..32d2f3b26cb03 100644 --- a/tests/ui/delegation/bad-resolve.stderr +++ b/tests/ui/delegation/bad-resolve.stderr @@ -25,6 +25,15 @@ LL | reuse ::baz; | | help: there is an associated function with a similar name: `bar` | not a member of trait `Trait` +error[E0407]: method `foo2` is not a member of trait `Trait` + --> $DIR/bad-resolve.rs:37:5 + | +LL | reuse Trait::foo2 { self.0 } + | ^^^^^^^^^^^^^----^^^^^^^^^^^ + | | | + | | help: there is an associated function with a similar name: `foo` + | not a member of trait `Trait` + error[E0423]: expected function, found associated constant `Trait::C` --> $DIR/bad-resolve.rs:24:11 | @@ -54,6 +63,15 @@ error[E0425]: cannot find function `foo` in this scope LL | reuse foo { &self.0 } | ^^^ not found in this scope +error[E0425]: cannot find function `foo2` in trait `Trait` + --> $DIR/bad-resolve.rs:37:18 + | +LL | fn foo(&self, x: i32) -> i32 { x } + | ---------------------------- similarly named associated function `foo` defined here +... +LL | reuse Trait::foo2 { self.0 } + | ^^^^ help: an associated function with a similar name exists: `foo` + error[E0046]: not all trait items implemented, missing: `Type` --> $DIR/bad-resolve.rs:22:1 | @@ -64,18 +82,18 @@ LL | impl Trait for S { | ^^^^^^^^^^^^^^^^ missing `Type` in implementation error[E0433]: failed to resolve: use of undeclared crate or module `unresolved_prefix` - --> $DIR/bad-resolve.rs:40:7 + --> $DIR/bad-resolve.rs:43:7 | LL | reuse unresolved_prefix::{a, b, c}; | ^^^^^^^^^^^^^^^^^ use of undeclared crate or module `unresolved_prefix` error[E0433]: failed to resolve: `crate` in paths can only be used in start position - --> $DIR/bad-resolve.rs:41:29 + --> $DIR/bad-resolve.rs:44:29 | LL | reuse prefix::{self, super, crate}; | ^^^^^ `crate` in paths can only be used in start position -error: aborting due to 10 previous errors +error: aborting due to 12 previous errors Some errors have detailed explanations: E0046, E0324, E0407, E0423, E0425, E0433, E0575, E0576. For more information about an error, try `rustc --explain E0046`. diff --git a/tests/ui/delegation/explicit-paths-pass.rs b/tests/ui/delegation/explicit-paths-pass.rs index fada793bd118c..dd0ee2c732f59 100644 --- a/tests/ui/delegation/explicit-paths-pass.rs +++ b/tests/ui/delegation/explicit-paths-pass.rs @@ -24,8 +24,8 @@ reuse to_reuse::zero_args { self } struct S(F); impl Trait for S { - reuse Trait::bar { &self.0 } - reuse Trait::description { &self.0 } + reuse Trait::bar { self.0 } + reuse Trait::description { self.0 } reuse ::static_method; reuse ::static_method2 { S::static_method(self) } } diff --git a/tests/ui/delegation/explicit-paths.rs b/tests/ui/delegation/explicit-paths.rs index a91ca4cb931ed..d42e305b252f0 100644 --- a/tests/ui/delegation/explicit-paths.rs +++ b/tests/ui/delegation/explicit-paths.rs @@ -34,7 +34,7 @@ mod inherent_impl_assoc_fn_to_other { use crate::*; impl S { - reuse Trait::foo1 { &self.0 } + reuse Trait::foo1 { self.0 } reuse ::foo2; reuse to_reuse::foo3; reuse F::foo4 { &self.0 } @@ -46,7 +46,7 @@ mod trait_impl_assoc_fn_to_other { use crate::*; impl Trait for S { - reuse Trait::foo1 { &self.0 } + reuse Trait::foo1 { self.0 } reuse ::foo2; reuse to_reuse::foo3; //~^ ERROR method `foo3` is not a member of trait `Trait` diff --git a/tests/ui/delegation/explicit-paths.stderr b/tests/ui/delegation/explicit-paths.stderr index 30891c94c0e98..d33c5da4377b1 100644 --- a/tests/ui/delegation/explicit-paths.stderr +++ b/tests/ui/delegation/explicit-paths.stderr @@ -110,10 +110,10 @@ error[E0308]: mismatched types --> $DIR/explicit-paths.rs:78:30 | LL | reuse ::foo1; - | ---------------^^^^ - | | | - | | expected `&S2`, found `&S` - | arguments to this function are incorrect + | ^^^^ + | | + | expected `&S2`, found `&S` + | arguments to this function are incorrect | = note: expected reference `&S2` found reference `&S` diff --git a/tests/ui/delegation/glob-glob.rs b/tests/ui/delegation/glob-glob.rs index ef7f9a15e1955..34e048f99f544 100644 --- a/tests/ui/delegation/glob-glob.rs +++ b/tests/ui/delegation/glob-glob.rs @@ -19,6 +19,8 @@ mod inner { } } +use inner::*; + trait Trait { fn foo(&self) -> u8; fn bar(&self) -> u8; @@ -31,6 +33,6 @@ impl Trait for u8 { fn main() { let u = 0u8; - u.foo(); - u.bar(); + ::foo(&u); + ::bar(&u); } diff --git a/tests/ui/delegation/method-call-priority.rs b/tests/ui/delegation/method-call-priority.rs new file mode 100644 index 0000000000000..0a4ea57f642ce --- /dev/null +++ b/tests/ui/delegation/method-call-priority.rs @@ -0,0 +1,32 @@ +//@ run-pass + +#![feature(fn_delegation)] +#![allow(incomplete_features)] +#![allow(dead_code)] + +trait Trait1 { + fn foo(&self) -> i32 { 1 } +} + +trait Trait2 { + fn foo(&self) -> i32 { 2 } +} + +struct F; +impl Trait1 for F {} +impl Trait2 for F {} + +impl F { + fn foo(&self) -> i32 { 3 } +} + +struct S(F); + +impl Trait1 for S { + reuse Trait1::foo { self.0 } +} + +fn main() { + let s = S(F); + assert_eq!(s.foo(), 1); +} diff --git a/tests/ui/delegation/self-coercion.rs b/tests/ui/delegation/self-coercion.rs new file mode 100644 index 0000000000000..96c1f1b140b14 --- /dev/null +++ b/tests/ui/delegation/self-coercion.rs @@ -0,0 +1,26 @@ +//@ run-pass + +#![feature(fn_delegation)] +#![allow(incomplete_features)] + +trait Trait : Sized { + fn by_value(self) -> i32 { 1 } + fn by_mut_ref(&mut self) -> i32 { 2 } + fn by_ref(&self) -> i32 { 3 } +} + +struct F; +impl Trait for F {} + +struct S(F); + +impl Trait for S { + reuse Trait::{by_value, by_mut_ref, by_ref} { self.0 } +} + +fn main() { + let mut s = S(F); + assert_eq!(s.by_ref(), 3); + assert_eq!(s.by_mut_ref(), 2); + assert_eq!(s.by_value(), 1); +} diff --git a/tests/ui/delegation/target-expr.rs b/tests/ui/delegation/target-expr.rs index fd7ea943b9d5e..bc147d78c2f7a 100644 --- a/tests/ui/delegation/target-expr.rs +++ b/tests/ui/delegation/target-expr.rs @@ -3,12 +3,16 @@ trait Trait { fn static_method(x: i32) -> i32 { x } + fn foo(&self) {} } struct F; struct S(F); -impl Trait for S {} +impl Trait for S { + reuse Trait::foo { self.0; } + //~^ ERROR no method named `foo` found for unit type `()` in the current scope +} fn foo(x: i32) -> i32 { x } diff --git a/tests/ui/delegation/target-expr.stderr b/tests/ui/delegation/target-expr.stderr index b30f0c474c68b..d4dbdc500bfe9 100644 --- a/tests/ui/delegation/target-expr.stderr +++ b/tests/ui/delegation/target-expr.stderr @@ -1,5 +1,5 @@ error[E0401]: can't use generic parameters from outer item - --> $DIR/target-expr.rs:20:17 + --> $DIR/target-expr.rs:24:17 | LL | fn bar(_: T) { | - type parameter from outer item @@ -10,7 +10,7 @@ LL | let _ = T::Default(); | ^^^^^^^^^^ use of generic parameter from outer item error[E0434]: can't capture dynamic environment in a fn item - --> $DIR/target-expr.rs:29:17 + --> $DIR/target-expr.rs:33:17 | LL | let x = y; | ^ @@ -18,7 +18,7 @@ LL | let x = y; = help: use the `|| { ... }` closure form instead error[E0424]: expected value, found module `self` - --> $DIR/target-expr.rs:36:5 + --> $DIR/target-expr.rs:40:5 | LL | fn main() { | ---- this function can't have a `self` parameter @@ -27,19 +27,19 @@ LL | self.0; | ^^^^ `self` value is a keyword only available in methods with a `self` parameter error[E0425]: cannot find value `x` in this scope - --> $DIR/target-expr.rs:38:13 + --> $DIR/target-expr.rs:42:13 | LL | let z = x; | ^ | help: the binding `x` is available in a different scope in the same function - --> $DIR/target-expr.rs:29:13 + --> $DIR/target-expr.rs:33:13 | LL | let x = y; | ^ error: delegation with early bound generics is not supported yet - --> $DIR/target-expr.rs:16:18 + --> $DIR/target-expr.rs:20:18 | LL | fn static_method(x: i32) -> i32 { x } | ------------------------------- callee defined here @@ -48,7 +48,7 @@ LL | reuse Trait::static_method { | ^^^^^^^^^^^^^ error: delegation to a trait method from a free function is not supported yet - --> $DIR/target-expr.rs:16:18 + --> $DIR/target-expr.rs:20:18 | LL | fn static_method(x: i32) -> i32 { x } | ------------------------------- callee defined here @@ -57,7 +57,7 @@ LL | reuse Trait::static_method { | ^^^^^^^^^^^^^ error: delegation to a trait method from a free function is not supported yet - --> $DIR/target-expr.rs:27:25 + --> $DIR/target-expr.rs:31:25 | LL | fn static_method(x: i32) -> i32 { x } | ------------------------------- callee defined here @@ -65,8 +65,21 @@ LL | fn static_method(x: i32) -> i32 { x } LL | reuse ::static_method { | ^^^^^^^^^^^^^ +error[E0599]: no method named `foo` found for unit type `()` in the current scope + --> $DIR/target-expr.rs:13:18 + | +LL | reuse Trait::foo { self.0; } + | ^^^ method not found in `()` + | + = help: items from traits can only be used if the trait is implemented and in scope +note: `Trait` defines an item `foo`, perhaps you need to implement it + --> $DIR/target-expr.rs:4:1 + | +LL | trait Trait { + | ^^^^^^^^^^^ + error[E0308]: mismatched types - --> $DIR/target-expr.rs:16:32 + --> $DIR/target-expr.rs:20:32 | LL | reuse Trait::static_method { | ________________________________^ @@ -78,7 +91,7 @@ LL | | LL | | } | |_____^ expected `i32`, found `()` -error: aborting due to 8 previous errors +error: aborting due to 9 previous errors -Some errors have detailed explanations: E0308, E0401, E0424, E0425, E0434. +Some errors have detailed explanations: E0308, E0401, E0424, E0425, E0434, E0599. For more information about an error, try `rustc --explain E0308`.