Rollup merge of #126699 - Bryanskiy:delegation-coercion, r=compiler-errors
Delegation: support coercion for target expression (solves https://github.com/rust-lang/rust/issues/118212#issuecomment-2160723092) The implementation consist of 2 parts. Firstly, method call is generated instead of fully qualified call in AST->HIR lowering if there were no generic arguments or `Qpath` were provided. These restrictions are imposed due to the loss of information after desugaring. For example in ```rust trait Trait { fn foo(&self) {} } reuse <u8 as Trait>::foo; ``` We would like to generate such a code: ```rust fn foo<u8: Trait>(x: &u8) { x.foo(x) } ``` however, the signature is inherited during HIR analysis where `u8` was discarded. Then, we probe the single pre-resolved method. P.S In the future, we would like to avoid restrictions on the callee path by `Self` autoref/autoderef in fully qualified calls, but at the moment it didn't work out. r? `@petrochenkov`
This commit is contained in:
commit
36ea06827b
@ -38,7 +38,7 @@
|
|||||||
|
|
||||||
use crate::{ImplTraitPosition, ResolverAstLoweringExt};
|
use crate::{ImplTraitPosition, ResolverAstLoweringExt};
|
||||||
|
|
||||||
use super::{ImplTraitContext, LoweringContext, ParamMode};
|
use super::{ImplTraitContext, LoweringContext, ParamMode, ParenthesizedGenericArgs};
|
||||||
|
|
||||||
use ast::visit::Visitor;
|
use ast::visit::Visitor;
|
||||||
use hir::def::{DefKind, PartialRes, Res};
|
use hir::def::{DefKind, PartialRes, Res};
|
||||||
@ -259,8 +259,7 @@ fn lower_delegation_body(
|
|||||||
self_param_id: pat_node_id,
|
self_param_id: pat_node_id,
|
||||||
};
|
};
|
||||||
self_resolver.visit_block(block);
|
self_resolver.visit_block(block);
|
||||||
let block = this.lower_block(block, false);
|
this.lower_target_expr(&block)
|
||||||
this.mk_expr(hir::ExprKind::Block(block, None), block.span)
|
|
||||||
} else {
|
} else {
|
||||||
let pat_hir_id = this.lower_node_id(pat_node_id);
|
let pat_hir_id = this.lower_node_id(pat_node_id);
|
||||||
this.generate_arg(pat_hir_id, span)
|
this.generate_arg(pat_hir_id, span)
|
||||||
@ -273,13 +272,69 @@ fn lower_delegation_body(
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generates fully qualified call for the resulting body.
|
// FIXME(fn_delegation): Alternatives for target expression lowering:
|
||||||
|
// https://github.com/rust-lang/rfcs/pull/3530#issuecomment-2197170600.
|
||||||
|
fn lower_target_expr(&mut self, block: &Block) -> hir::Expr<'hir> {
|
||||||
|
if block.stmts.len() == 1
|
||||||
|
&& let StmtKind::Expr(expr) = &block.stmts[0].kind
|
||||||
|
{
|
||||||
|
return self.lower_expr_mut(expr);
|
||||||
|
}
|
||||||
|
|
||||||
|
let block = self.lower_block(block, false);
|
||||||
|
self.mk_expr(hir::ExprKind::Block(block, None), block.span)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generates expression for the resulting body. If possible, `MethodCall` is 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.
|
||||||
fn finalize_body_lowering(
|
fn finalize_body_lowering(
|
||||||
&mut self,
|
&mut self,
|
||||||
delegation: &Delegation,
|
delegation: &Delegation,
|
||||||
args: Vec<hir::Expr<'hir>>,
|
args: Vec<hir::Expr<'hir>>,
|
||||||
span: Span,
|
span: Span,
|
||||||
) -> hir::Expr<'hir> {
|
) -> hir::Expr<'hir> {
|
||||||
|
let args = self.arena.alloc_from_iter(args);
|
||||||
|
|
||||||
|
let has_generic_args =
|
||||||
|
delegation.path.segments.iter().rev().skip(1).any(|segment| segment.args.is_some());
|
||||||
|
|
||||||
|
let call = 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()
|
||||||
|
&& !has_generic_args
|
||||||
|
{
|
||||||
|
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,
|
||||||
|
);
|
||||||
|
let segment = self.arena.alloc(segment);
|
||||||
|
|
||||||
|
self.arena.alloc(hir::Expr {
|
||||||
|
hir_id: self.next_id(),
|
||||||
|
kind: hir::ExprKind::MethodCall(segment, &args[0], &args[1..], span),
|
||||||
|
span,
|
||||||
|
})
|
||||||
|
} else {
|
||||||
let path = self.lower_qpath(
|
let path = self.lower_qpath(
|
||||||
delegation.id,
|
delegation.id,
|
||||||
&delegation.qself,
|
&delegation.qself,
|
||||||
@ -289,10 +344,9 @@ fn finalize_body_lowering(
|
|||||||
None,
|
None,
|
||||||
);
|
);
|
||||||
|
|
||||||
let args = self.arena.alloc_from_iter(args);
|
let callee_path = self.arena.alloc(self.mk_expr(hir::ExprKind::Path(path), span));
|
||||||
let path_expr = self.arena.alloc(self.mk_expr(hir::ExprKind::Path(path), span));
|
self.arena.alloc(self.mk_expr(hir::ExprKind::Call(callee_path, args), span))
|
||||||
let call = self.arena.alloc(self.mk_expr(hir::ExprKind::Call(path_expr, args), span));
|
};
|
||||||
|
|
||||||
let block = self.arena.alloc(hir::Block {
|
let block = self.arena.alloc(hir::Block {
|
||||||
stmts: &[],
|
stmts: &[],
|
||||||
expr: Some(call),
|
expr: Some(call),
|
||||||
|
@ -182,8 +182,13 @@ pub fn lookup_method(
|
|||||||
self_expr: &'tcx hir::Expr<'tcx>,
|
self_expr: &'tcx hir::Expr<'tcx>,
|
||||||
args: &'tcx [hir::Expr<'tcx>],
|
args: &'tcx [hir::Expr<'tcx>],
|
||||||
) -> Result<MethodCallee<'tcx>, MethodError<'tcx>> {
|
) -> Result<MethodCallee<'tcx>, MethodError<'tcx>> {
|
||||||
let pick =
|
let scope = if let Some(only_method) = segment.res.opt_def_id() {
|
||||||
self.lookup_probe(segment.ident, self_ty, call_expr, ProbeScope::TraitsInScope)?;
|
ProbeScope::Single(only_method)
|
||||||
|
} else {
|
||||||
|
ProbeScope::TraitsInScope
|
||||||
|
};
|
||||||
|
|
||||||
|
let pick = self.lookup_probe(segment.ident, self_ty, call_expr, scope)?;
|
||||||
|
|
||||||
self.lint_edition_dependent_dot_call(
|
self.lint_edition_dependent_dot_call(
|
||||||
self_ty, segment, span, call_expr, self_expr, &pick, args,
|
self_ty, segment, span, call_expr, self_expr, &pick, args,
|
||||||
|
@ -20,6 +20,7 @@
|
|||||||
use rustc_middle::query::Providers;
|
use rustc_middle::query::Providers;
|
||||||
use rustc_middle::ty::fast_reject::{simplify_type, TreatParams};
|
use rustc_middle::ty::fast_reject::{simplify_type, TreatParams};
|
||||||
use rustc_middle::ty::AssocItem;
|
use rustc_middle::ty::AssocItem;
|
||||||
|
use rustc_middle::ty::AssocItemContainer;
|
||||||
use rustc_middle::ty::GenericParamDefKind;
|
use rustc_middle::ty::GenericParamDefKind;
|
||||||
use rustc_middle::ty::Upcast;
|
use rustc_middle::ty::Upcast;
|
||||||
use rustc_middle::ty::{self, ParamEnvAnd, Ty, TyCtxt, TypeVisitableExt};
|
use rustc_middle::ty::{self, ParamEnvAnd, Ty, TyCtxt, TypeVisitableExt};
|
||||||
@ -216,6 +217,9 @@ pub enum Mode {
|
|||||||
|
|
||||||
#[derive(PartialEq, Eq, Copy, Clone, Debug)]
|
#[derive(PartialEq, Eq, Copy, Clone, Debug)]
|
||||||
pub enum ProbeScope {
|
pub enum ProbeScope {
|
||||||
|
// Single candidate coming from pre-resolved delegation method.
|
||||||
|
Single(DefId),
|
||||||
|
|
||||||
// Assemble candidates coming only from traits in scope.
|
// Assemble candidates coming only from traits in scope.
|
||||||
TraitsInScope,
|
TraitsInScope,
|
||||||
|
|
||||||
@ -480,12 +484,35 @@ pub(crate) fn probe_op<OP, R>(
|
|||||||
is_suggestion,
|
is_suggestion,
|
||||||
);
|
);
|
||||||
|
|
||||||
probe_cx.assemble_inherent_candidates();
|
|
||||||
match scope {
|
match scope {
|
||||||
ProbeScope::TraitsInScope => {
|
ProbeScope::TraitsInScope => {
|
||||||
probe_cx.assemble_extension_candidates_for_traits_in_scope()
|
probe_cx.assemble_inherent_candidates();
|
||||||
|
probe_cx.assemble_extension_candidates_for_traits_in_scope();
|
||||||
|
}
|
||||||
|
ProbeScope::AllTraits => {
|
||||||
|
probe_cx.assemble_inherent_candidates();
|
||||||
|
probe_cx.assemble_extension_candidates_for_all_traits();
|
||||||
|
}
|
||||||
|
ProbeScope::Single(def_id) => {
|
||||||
|
let item = self.tcx.associated_item(def_id);
|
||||||
|
// FIXME(fn_delegation): Delegation to inherent methods is not yet supported.
|
||||||
|
assert_eq!(item.container, AssocItemContainer::TraitContainer);
|
||||||
|
|
||||||
|
let trait_def_id = self.tcx.parent(def_id);
|
||||||
|
let trait_span = self.tcx.def_span(trait_def_id);
|
||||||
|
|
||||||
|
let trait_args = self.fresh_args_for_item(trait_span, trait_def_id);
|
||||||
|
let trait_ref = ty::TraitRef::new_from_args(self.tcx, trait_def_id, trait_args);
|
||||||
|
|
||||||
|
probe_cx.push_candidate(
|
||||||
|
Candidate {
|
||||||
|
item,
|
||||||
|
kind: CandidateKind::TraitCandidate(ty::Binder::dummy(trait_ref)),
|
||||||
|
import_ids: smallvec![],
|
||||||
|
},
|
||||||
|
false,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
ProbeScope::AllTraits => probe_cx.assemble_extension_candidates_for_all_traits(),
|
|
||||||
};
|
};
|
||||||
op(probe_cx)
|
op(probe_cx)
|
||||||
})
|
})
|
||||||
|
@ -34,6 +34,9 @@ impl Trait for S {
|
|||||||
|
|
||||||
reuse foo { &self.0 }
|
reuse foo { &self.0 }
|
||||||
//~^ ERROR cannot find function `foo` in this scope
|
//~^ 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 {}
|
mod prefix {}
|
||||||
|
@ -25,6 +25,15 @@ LL | reuse <F as Trait>::baz;
|
|||||||
| | help: there is an associated function with a similar name: `bar`
|
| | help: there is an associated function with a similar name: `bar`
|
||||||
| not a member of trait `Trait`
|
| 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`
|
error[E0423]: expected function, found associated constant `Trait::C`
|
||||||
--> $DIR/bad-resolve.rs:24:11
|
--> $DIR/bad-resolve.rs:24:11
|
||||||
|
|
|
|
||||||
@ -54,6 +63,15 @@ error[E0425]: cannot find function `foo` in this scope
|
|||||||
LL | reuse foo { &self.0 }
|
LL | reuse foo { &self.0 }
|
||||||
| ^^^ not found in this scope
|
| ^^^ 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`
|
error[E0046]: not all trait items implemented, missing: `Type`
|
||||||
--> $DIR/bad-resolve.rs:22:1
|
--> $DIR/bad-resolve.rs:22:1
|
||||||
|
|
|
|
||||||
@ -64,18 +82,18 @@ LL | impl Trait for S {
|
|||||||
| ^^^^^^^^^^^^^^^^ missing `Type` in implementation
|
| ^^^^^^^^^^^^^^^^ missing `Type` in implementation
|
||||||
|
|
||||||
error[E0433]: failed to resolve: use of undeclared crate or module `unresolved_prefix`
|
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};
|
LL | reuse unresolved_prefix::{a, b, c};
|
||||||
| ^^^^^^^^^^^^^^^^^ use of undeclared crate or module `unresolved_prefix`
|
| ^^^^^^^^^^^^^^^^^ use of undeclared crate or module `unresolved_prefix`
|
||||||
|
|
||||||
error[E0433]: failed to resolve: `crate` in paths can only be used in start position
|
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};
|
LL | reuse prefix::{self, super, crate};
|
||||||
| ^^^^^ `crate` in paths can only be used in start position
|
| ^^^^^ `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.
|
Some errors have detailed explanations: E0046, E0324, E0407, E0423, E0425, E0433, E0575, E0576.
|
||||||
For more information about an error, try `rustc --explain E0046`.
|
For more information about an error, try `rustc --explain E0046`.
|
||||||
|
@ -24,8 +24,8 @@ pub fn zero_args() -> i32 { 15 }
|
|||||||
|
|
||||||
struct S(F);
|
struct S(F);
|
||||||
impl Trait for S {
|
impl Trait for S {
|
||||||
reuse Trait::bar { &self.0 }
|
reuse Trait::bar { self.0 }
|
||||||
reuse Trait::description { &self.0 }
|
reuse Trait::description { self.0 }
|
||||||
reuse <F as Trait>::static_method;
|
reuse <F as Trait>::static_method;
|
||||||
reuse <F as Trait>::static_method2 { S::static_method(self) }
|
reuse <F as Trait>::static_method2 { S::static_method(self) }
|
||||||
}
|
}
|
||||||
|
@ -34,7 +34,7 @@ mod inherent_impl_assoc_fn_to_other {
|
|||||||
use crate::*;
|
use crate::*;
|
||||||
|
|
||||||
impl S {
|
impl S {
|
||||||
reuse Trait::foo1 { &self.0 }
|
reuse Trait::foo1 { self.0 }
|
||||||
reuse <S as Trait>::foo2;
|
reuse <S as Trait>::foo2;
|
||||||
reuse to_reuse::foo3;
|
reuse to_reuse::foo3;
|
||||||
reuse F::foo4 { &self.0 }
|
reuse F::foo4 { &self.0 }
|
||||||
@ -46,7 +46,7 @@ mod trait_impl_assoc_fn_to_other {
|
|||||||
use crate::*;
|
use crate::*;
|
||||||
|
|
||||||
impl Trait for S {
|
impl Trait for S {
|
||||||
reuse Trait::foo1 { &self.0 }
|
reuse Trait::foo1 { self.0 }
|
||||||
reuse <F as Trait>::foo2;
|
reuse <F as Trait>::foo2;
|
||||||
reuse to_reuse::foo3;
|
reuse to_reuse::foo3;
|
||||||
//~^ ERROR method `foo3` is not a member of trait `Trait`
|
//~^ ERROR method `foo3` is not a member of trait `Trait`
|
||||||
|
@ -91,10 +91,17 @@ error[E0308]: mismatched types
|
|||||||
LL | trait Trait2 : Trait {
|
LL | trait Trait2 : Trait {
|
||||||
| -------------------- found this type parameter
|
| -------------------- found this type parameter
|
||||||
LL | reuse <F as Trait>::foo1 { self }
|
LL | reuse <F as Trait>::foo1 { self }
|
||||||
| ^^^^ expected `&F`, found `&Self`
|
| ---- ^^^^ expected `&F`, found `&Self`
|
||||||
|
| |
|
||||||
|
| arguments to this function are incorrect
|
||||||
|
|
|
|
||||||
= note: expected reference `&F`
|
= note: expected reference `&F`
|
||||||
found reference `&Self`
|
found reference `&Self`
|
||||||
|
note: method defined here
|
||||||
|
--> $DIR/explicit-paths.rs:5:8
|
||||||
|
|
|
||||||
|
LL | fn foo1(&self, x: i32) -> i32 { x }
|
||||||
|
| ^^^^ -----
|
||||||
|
|
||||||
error[E0277]: the trait bound `S2: Trait` is not satisfied
|
error[E0277]: the trait bound `S2: Trait` is not satisfied
|
||||||
--> $DIR/explicit-paths.rs:78:16
|
--> $DIR/explicit-paths.rs:78:16
|
||||||
|
@ -4,15 +4,6 @@ error[E0308]: mismatched types
|
|||||||
LL | fn description(&self) -> &str {}
|
LL | fn description(&self) -> &str {}
|
||||||
| ^^ expected `&str`, found `()`
|
| ^^ expected `&str`, found `()`
|
||||||
|
|
||||||
error[E0308]: mismatched types
|
|
||||||
--> $DIR/ice-issue-122550.rs:13:39
|
|
||||||
|
|
|
||||||
LL | reuse <S as Trait>::description { &self.0 }
|
|
||||||
| ^^^^^^^ expected `&S`, found `&F`
|
|
||||||
|
|
|
||||||
= note: expected reference `&S`
|
|
||||||
found reference `&F`
|
|
||||||
|
|
||||||
error[E0277]: the trait bound `S: Trait` is not satisfied
|
error[E0277]: the trait bound `S: Trait` is not satisfied
|
||||||
--> $DIR/ice-issue-122550.rs:13:12
|
--> $DIR/ice-issue-122550.rs:13:12
|
||||||
|
|
|
|
||||||
@ -25,6 +16,22 @@ help: this trait has no implementations, consider adding one
|
|||||||
LL | trait Trait {
|
LL | trait Trait {
|
||||||
| ^^^^^^^^^^^
|
| ^^^^^^^^^^^
|
||||||
|
|
||||||
|
error[E0308]: mismatched types
|
||||||
|
--> $DIR/ice-issue-122550.rs:13:39
|
||||||
|
|
|
||||||
|
LL | reuse <S as Trait>::description { &self.0 }
|
||||||
|
| ----------- ^^^^^^^ expected `&S`, found `&F`
|
||||||
|
| |
|
||||||
|
| arguments to this function are incorrect
|
||||||
|
|
|
||||||
|
= note: expected reference `&S`
|
||||||
|
found reference `&F`
|
||||||
|
note: method defined here
|
||||||
|
--> $DIR/ice-issue-122550.rs:5:8
|
||||||
|
|
|
||||||
|
LL | fn description(&self) -> &str {}
|
||||||
|
| ^^^^^^^^^^^ -----
|
||||||
|
|
||||||
error: aborting due to 3 previous errors
|
error: aborting due to 3 previous errors
|
||||||
|
|
||||||
Some errors have detailed explanations: E0277, E0308.
|
Some errors have detailed explanations: E0277, E0308.
|
||||||
|
25
tests/ui/delegation/method-call-choice.rs
Normal file
25
tests/ui/delegation/method-call-choice.rs
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
#![feature(fn_delegation)]
|
||||||
|
#![allow(incomplete_features)]
|
||||||
|
|
||||||
|
trait Trait {
|
||||||
|
fn foo(&self) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct F;
|
||||||
|
impl Trait for F {}
|
||||||
|
struct S(F);
|
||||||
|
|
||||||
|
pub mod to_reuse {
|
||||||
|
use crate::F;
|
||||||
|
|
||||||
|
pub fn foo(_: &F) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Trait for S {
|
||||||
|
// Make sure that the method call is not generated if the path resolution
|
||||||
|
// does not have a `self` parameter.
|
||||||
|
reuse to_reuse::foo { self.0 }
|
||||||
|
//~^ ERROR mismatched types
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
21
tests/ui/delegation/method-call-choice.stderr
Normal file
21
tests/ui/delegation/method-call-choice.stderr
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
error[E0308]: mismatched types
|
||||||
|
--> $DIR/method-call-choice.rs:21:27
|
||||||
|
|
|
||||||
|
LL | reuse to_reuse::foo { self.0 }
|
||||||
|
| --- ^^^^^^ expected `&F`, found `F`
|
||||||
|
| |
|
||||||
|
| arguments to this function are incorrect
|
||||||
|
|
|
||||||
|
note: function defined here
|
||||||
|
--> $DIR/method-call-choice.rs:15:12
|
||||||
|
|
|
||||||
|
LL | pub fn foo(_: &F) {}
|
||||||
|
| ^^^ -----
|
||||||
|
help: consider borrowing here
|
||||||
|
|
|
||||||
|
LL | reuse to_reuse::foo { &self.0 }
|
||||||
|
| +
|
||||||
|
|
||||||
|
error: aborting due to 1 previous error
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0308`.
|
34
tests/ui/delegation/method-call-priority.rs
Normal file
34
tests/ui/delegation/method-call-priority.rs
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
//@ 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 {
|
||||||
|
// Make sure that the generated `self.0.foo()` does not turn into the inherent method `F::foo`
|
||||||
|
// that has a higher priority than methods from traits.
|
||||||
|
reuse Trait1::foo { self.0 }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let s = S(F);
|
||||||
|
assert_eq!(s.foo(), 1);
|
||||||
|
}
|
26
tests/ui/delegation/self-coercion.rs
Normal file
26
tests/ui/delegation/self-coercion.rs
Normal file
@ -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);
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user