1
Fork 0

Support RTN on associated methods from supertraits

This commit is contained in:
Michael Goulet 2023-05-03 19:39:57 +00:00
parent 82cd953c7c
commit 20a83144b2
9 changed files with 115 additions and 31 deletions

View file

@ -192,7 +192,7 @@ hir_analysis_return_type_notation_equality_bound =
return type notation is not allowed to use type equality return type notation is not allowed to use type equality
hir_analysis_return_type_notation_missing_method = hir_analysis_return_type_notation_missing_method =
cannot find associated function `{$assoc_name}` in trait `{$trait_name}` cannot find associated function `{$assoc_name}` for `{$ty_name}`
hir_analysis_placeholder_not_allowed_item_signatures = the placeholder `_` is not allowed within types on item signatures for {$kind} hir_analysis_placeholder_not_allowed_item_signatures = the placeholder `_` is not allowed within types on item signatures for {$kind}
.label = not allowed in type signatures .label = not allowed in type signatures

View file

@ -1118,11 +1118,12 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
) { ) {
trait_ref trait_ref
} else { } else {
return Err(tcx.sess.emit_err(crate::errors::ReturnTypeNotationMissingMethod { self.one_bound_for_assoc_method(
span: binding.span, traits::supertraits(tcx, trait_ref),
trait_name: tcx.item_name(trait_ref.def_id()), trait_ref.print_only_trait_path(),
assoc_name: binding.item_name.name, binding.item_name,
})); path_span,
)?
} }
} else if self.trait_defines_associated_item_named( } else if self.trait_defines_associated_item_named(
trait_ref.def_id(), trait_ref.def_id(),
@ -2057,6 +2058,38 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
Ok(bound) Ok(bound)
} }
#[instrument(level = "debug", skip(self, all_candidates, ty_name), ret)]
fn one_bound_for_assoc_method(
&self,
all_candidates: impl Iterator<Item = ty::PolyTraitRef<'tcx>>,
ty_name: impl Display,
assoc_name: Ident,
span: Span,
) -> Result<ty::PolyTraitRef<'tcx>, ErrorGuaranteed> {
let mut matching_candidates = all_candidates.filter(|r| {
self.trait_defines_associated_item_named(r.def_id(), ty::AssocKind::Fn, assoc_name)
});
let candidate = match matching_candidates.next() {
Some(candidate) => candidate,
None => {
return Err(self.tcx().sess.emit_err(
crate::errors::ReturnTypeNotationMissingMethod {
span,
ty_name: ty_name.to_string(),
assoc_name: assoc_name.name,
},
));
}
};
if let Some(_conflicting_candidate) = matching_candidates.next() {
todo!()
}
Ok(candidate)
}
// Create a type from a path to an associated type or to an enum variant. // Create a type from a path to an associated type or to an enum variant.
// For a path `A::B::C::D`, `qself_ty` and `qself_def` are the type and def for `A::B::C` // For a path `A::B::C::D`, `qself_ty` and `qself_def` are the type and def for `A::B::C`
// and item_segment is the path segment for `D`. We return a type and a def for // and item_segment is the path segment for `D`. We return a type and a def for

View file

@ -1652,17 +1652,16 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
if binding.gen_args.parenthesized == hir::GenericArgsParentheses::ReturnTypeNotation { if binding.gen_args.parenthesized == hir::GenericArgsParentheses::ReturnTypeNotation {
let bound_vars = if let Some(type_def_id) = type_def_id let bound_vars = if let Some(type_def_id) = type_def_id
&& self.tcx.def_kind(type_def_id) == DefKind::Trait && self.tcx.def_kind(type_def_id) == DefKind::Trait
// FIXME(return_type_notation): We could bound supertrait methods. && let Some((mut bound_vars, assoc_fn)) =
&& let Some(assoc_fn) = self BoundVarContext::supertrait_hrtb_vars(
.tcx self.tcx,
.associated_items(type_def_id) type_def_id,
.find_by_name_and_kind(self.tcx, binding.ident, ty::AssocKind::Fn, type_def_id) binding.ident,
ty::AssocKind::Fn,
)
{ {
self.tcx bound_vars.extend(self.tcx.generics_of(assoc_fn.def_id).params.iter().map(
.generics_of(assoc_fn.def_id) |param| match param.kind {
.params
.iter()
.map(|param| match param.kind {
ty::GenericParamDefKind::Lifetime => ty::BoundVariableKind::Region( ty::GenericParamDefKind::Lifetime => ty::BoundVariableKind::Region(
ty::BoundRegionKind::BrNamed(param.def_id, param.name), ty::BoundRegionKind::BrNamed(param.def_id, param.name),
), ),
@ -1670,9 +1669,11 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
ty::BoundTyKind::Param(param.def_id, param.name), ty::BoundTyKind::Param(param.def_id, param.name),
), ),
ty::GenericParamDefKind::Const { .. } => ty::BoundVariableKind::Const, ty::GenericParamDefKind::Const { .. } => ty::BoundVariableKind::Const,
}) },
.chain(self.tcx.fn_sig(assoc_fn.def_id).subst_identity().bound_vars()) ));
.collect() bound_vars
.extend(self.tcx.fn_sig(assoc_fn.def_id).subst_identity().bound_vars());
bound_vars
} else { } else {
self.tcx.sess.delay_span_bug( self.tcx.sess.delay_span_bug(
binding.ident.span, binding.ident.span,
@ -1689,8 +1690,13 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
}); });
}); });
} else if let Some(type_def_id) = type_def_id { } else if let Some(type_def_id) = type_def_id {
let bound_vars = let bound_vars = BoundVarContext::supertrait_hrtb_vars(
BoundVarContext::supertrait_hrtb_vars(self.tcx, type_def_id, binding.ident); self.tcx,
type_def_id,
binding.ident,
ty::AssocKind::Type,
)
.map(|(bound_vars, _)| bound_vars);
self.with(scope, |this| { self.with(scope, |this| {
let scope = Scope::Supertrait { let scope = Scope::Supertrait {
bound_vars: bound_vars.unwrap_or_default(), bound_vars: bound_vars.unwrap_or_default(),
@ -1720,11 +1726,15 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
tcx: TyCtxt<'tcx>, tcx: TyCtxt<'tcx>,
def_id: DefId, def_id: DefId,
assoc_name: Ident, assoc_name: Ident,
) -> Option<Vec<ty::BoundVariableKind>> { assoc_kind: ty::AssocKind,
) -> Option<(Vec<ty::BoundVariableKind>, &'tcx ty::AssocItem)> {
let trait_defines_associated_type_named = |trait_def_id: DefId| { let trait_defines_associated_type_named = |trait_def_id: DefId| {
tcx.associated_items(trait_def_id) tcx.associated_items(trait_def_id).find_by_name_and_kind(
.find_by_name_and_kind(tcx, assoc_name, ty::AssocKind::Type, trait_def_id) tcx,
.is_some() assoc_name,
assoc_kind,
trait_def_id,
)
}; };
use smallvec::{smallvec, SmallVec}; use smallvec::{smallvec, SmallVec};
@ -1742,8 +1752,8 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
_ => break None, _ => break None,
} }
if trait_defines_associated_type_named(def_id) { if let Some(assoc_item) = trait_defines_associated_type_named(def_id) {
break Some(bound_vars.into_iter().collect()); break Some((bound_vars.into_iter().collect(), assoc_item));
} }
let predicates = tcx.super_predicates_that_define_assoc_type((def_id, assoc_name)); let predicates = tcx.super_predicates_that_define_assoc_type((def_id, assoc_name));
let obligations = predicates.predicates.iter().filter_map(|&(pred, _)| { let obligations = predicates.predicates.iter().filter_map(|&(pred, _)| {

View file

@ -512,7 +512,7 @@ pub(crate) struct ReturnTypeNotationEqualityBound {
pub(crate) struct ReturnTypeNotationMissingMethod { pub(crate) struct ReturnTypeNotationMissingMethod {
#[primary_span] #[primary_span]
pub span: Span, pub span: Span,
pub trait_name: Symbol, pub ty_name: String,
pub assoc_name: Symbol, pub assoc_name: Symbol,
} }

View file

@ -1570,7 +1570,12 @@ impl<'tcx> TyCtxt<'tcx> {
pub fn trait_may_define_assoc_type(self, trait_def_id: DefId, assoc_name: Ident) -> bool { pub fn trait_may_define_assoc_type(self, trait_def_id: DefId, assoc_name: Ident) -> bool {
self.super_traits_of(trait_def_id).any(|trait_did| { self.super_traits_of(trait_def_id).any(|trait_did| {
self.associated_items(trait_did) self.associated_items(trait_did)
.find_by_name_and_kind(self, assoc_name, ty::AssocKind::Type, trait_did) .find_by_name_and_kinds(
self,
assoc_name,
&[ty::AssocKind::Type, ty::AssocKind::Const, ty::AssocKind::Fn],
trait_did,
)
.is_some() .is_some()
}) })
} }

View file

@ -8,6 +8,6 @@ trait Trait {
} }
fn bar<T: Trait<methid(): Send>>() {} fn bar<T: Trait<methid(): Send>>() {}
//~^ ERROR cannot find associated function `methid` in trait `Trait` //~^ ERROR cannot find associated function `methid` for `Trait`
fn main() {} fn main() {}

View file

@ -7,7 +7,7 @@ LL | #![feature(return_type_notation, async_fn_in_trait)]
= note: see issue #109417 <https://github.com/rust-lang/rust/issues/109417> for more information = note: see issue #109417 <https://github.com/rust-lang/rust/issues/109417> for more information
= note: `#[warn(incomplete_features)]` on by default = note: `#[warn(incomplete_features)]` on by default
error: cannot find associated function `methid` in trait `Trait` error: cannot find associated function `methid` for `Trait`
--> $DIR/missing.rs:10:17 --> $DIR/missing.rs:10:17
| |
LL | fn bar<T: Trait<methid(): Send>>() {} LL | fn bar<T: Trait<methid(): Send>>() {}

View file

@ -0,0 +1,25 @@
// edition:2021
// check-pass
#![feature(async_fn_in_trait, return_type_notation)]
//~^ WARN the feature `return_type_notation` is incomplete
trait Super<'a> {
async fn test();
}
impl Super<'_> for () {
async fn test() {}
}
trait Foo: for<'a> Super<'a> {}
impl Foo for () {}
fn test<T>()
where
T: Foo<test(): Send>,
{
}
fn main() {
test::<()>();
}

View file

@ -0,0 +1,11 @@
warning: the feature `return_type_notation` is incomplete and may not be safe to use and/or cause compiler crashes
--> $DIR/super-method-bound.rs:4:31
|
LL | #![feature(async_fn_in_trait, return_type_notation)]
| ^^^^^^^^^^^^^^^^^^^^
|
= note: see issue #109417 <https://github.com/rust-lang/rust/issues/109417> for more information
= note: `#[warn(incomplete_features)]` on by default
warning: 1 warning emitted