This commit is contained in:
Michael Goulet 2023-03-05 01:08:17 +00:00
parent fb9ca9223d
commit 773e8a5ad1
3 changed files with 120 additions and 51 deletions

View File

@ -987,8 +987,20 @@ fn lower_assoc_ty_constraint(
GenericArgs::AngleBracketed(data) => { GenericArgs::AngleBracketed(data) => {
self.lower_angle_bracketed_parameter_data(data, ParamMode::Explicit, itctx).0 self.lower_angle_bracketed_parameter_data(data, ParamMode::Explicit, itctx).0
} }
GenericArgs::Parenthesized(data)
if self.tcx.features().return_type_notation =>
{
// TODO: Check the parens + no return type
GenericArgsCtor {
args: Default::default(),
bindings: &[],
parenthesized: true,
span: data.span,
}
}
GenericArgs::Parenthesized(data) => { GenericArgs::Parenthesized(data) => {
self.emit_bad_parenthesized_trait_in_assoc_ty(data); self.emit_bad_parenthesized_trait_in_assoc_ty(data);
// TODO: Add a RTN feature error if the parens are shaped correctly
self.lower_angle_bracketed_parameter_data( self.lower_angle_bracketed_parameter_data(
&data.as_angle_bracketed_args(), &data.as_angle_bracketed_args(),
ParamMode::Explicit, ParamMode::Explicit,

View File

@ -854,16 +854,15 @@ fn create_substs_for_ast_trait_ref<'a>(
) )
} }
fn trait_defines_associated_type_named(&self, trait_def_id: DefId, assoc_name: Ident) -> bool { fn trait_defines_associated_item_named(
&self,
trait_def_id: DefId,
assoc_kind: ty::AssocKind,
assoc_name: Ident,
) -> bool {
self.tcx() self.tcx()
.associated_items(trait_def_id) .associated_items(trait_def_id)
.find_by_name_and_kind(self.tcx(), assoc_name, ty::AssocKind::Type, trait_def_id) .find_by_name_and_kind(self.tcx(), assoc_name, assoc_kind, trait_def_id)
.is_some()
}
fn trait_defines_associated_const_named(&self, trait_def_id: DefId, assoc_name: Ident) -> bool {
self.tcx()
.associated_items(trait_def_id)
.find_by_name_and_kind(self.tcx(), assoc_name, ty::AssocKind::Const, trait_def_id)
.is_some() .is_some()
} }
@ -1087,24 +1086,42 @@ fn add_predicates_for_ast_type_binding(
let tcx = self.tcx(); let tcx = self.tcx();
let candidate = // TODO: rtn comment goes here
if self.trait_defines_associated_type_named(trait_ref.def_id(), binding.item_name) { let associated_return_type_bound =
// Simple case: X is defined in the current trait. binding.gen_args.parenthesized && self.tcx().features().associated_return_type_bounds;
let candidate = if return_type_notation {
if self.trait_defines_associated_item_named(
trait_ref.def_id(),
ty::AssocKind::Fn,
binding.item_name,
) {
trait_ref trait_ref
} else { } else {
// Otherwise, we have to walk through the supertraits to find // TODO: error
// those that do. todo!()
self.one_bound_for_assoc_type( }
|| traits::supertraits(tcx, trait_ref), } else if self.trait_defines_associated_item_named(
trait_ref.print_only_trait_path(), trait_ref.def_id(),
binding.item_name, ty::AssocKind::Type,
path_span, binding.item_name,
match binding.kind { ) {
ConvertedBindingKind::Equality(term) => Some(term), // Simple case: X is defined in the current trait.
_ => None, trait_ref
}, } else {
)? // Otherwise, we have to walk through the supertraits to find
}; // those that do.
self.one_bound_for_assoc_type(
|| traits::supertraits(tcx, trait_ref),
trait_ref.print_only_trait_path(),
binding.item_name,
path_span,
match binding.kind {
ConvertedBindingKind::Equality(term) => Some(term),
_ => None,
},
)?
};
let (assoc_ident, def_scope) = let (assoc_ident, def_scope) =
tcx.adjust_ident_and_get_scope(binding.item_name, candidate.def_id(), hir_ref_id); tcx.adjust_ident_and_get_scope(binding.item_name, candidate.def_id(), hir_ref_id);
@ -1116,9 +1133,13 @@ fn add_predicates_for_ast_type_binding(
.filter_by_name_unhygienic(assoc_ident.name) .filter_by_name_unhygienic(assoc_ident.name)
.find(|i| i.kind == kind && i.ident(tcx).normalize_to_macros_2_0() == assoc_ident) .find(|i| i.kind == kind && i.ident(tcx).normalize_to_macros_2_0() == assoc_ident)
}; };
let assoc_item = find_item_of_kind(ty::AssocKind::Type) let assoc_item = if return_type_notation {
.or_else(|| find_item_of_kind(ty::AssocKind::Const)) find_item_of_kind(ty::AssocKind::Fn)
.expect("missing associated type"); } else {
find_item_of_kind(ty::AssocKind::Type)
.or_else(|| find_item_of_kind(ty::AssocKind::Const))
}
.expect("missing associated type");
if !assoc_item.visibility(tcx).is_accessible_from(def_scope, tcx) { if !assoc_item.visibility(tcx).is_accessible_from(def_scope, tcx) {
tcx.sess tcx.sess
@ -1145,28 +1166,54 @@ fn add_predicates_for_ast_type_binding(
.or_insert(binding.span); .or_insert(binding.span);
} }
// Include substitutions for generic parameters of associated types let projection_ty = if associated_return_type_bound {
let projection_ty = candidate.map_bound(|trait_ref| { let generics = self.tcx().generics_of(assoc_item.def_id);
let ident = Ident::new(assoc_item.name, binding.item_name.span); if !generics.params.is_empty() {
let item_segment = hir::PathSegment { todo!();
ident, }
hir_id: binding.hir_id, let output = self.tcx().fn_sig(assoc_item.def_id).skip_binder().output();
res: Res::Err, let fn_bound_vars = output.bound_vars();
args: Some(binding.gen_args),
infer_args: false, let output = if let ty::Alias(ty::Projection, alias_ty) = *output.skip_binder().kind()
&& tcx.def_kind(alias_ty.def_id) == DefKind::ImplTraitPlaceholder
{
alias_ty
} else {
todo!("found return type of {output:?}");
}; };
let substs_trait_ref_and_assoc_item = self.create_substs_for_associated_item( let trait_bound_vars = candidate.bound_vars();
path_span, let shifted_output = tcx.shift_bound_var_indices(trait_bound_vars.len(), output);
assoc_item.def_id, let subst_output =
&item_segment, ty::EarlyBinder(shifted_output).subst(tcx, candidate.skip_binder().substs);
trait_ref.substs, let bound_vars =
); tcx.mk_bound_variable_kinds_from_iter(trait_bound_vars.iter().chain(fn_bound_vars));
debug!(?substs_trait_ref_and_assoc_item); ty::Binder::bind_with_vars(subst_output, bound_vars)
} else {
// Include substitutions for generic parameters of associated types
candidate.map_bound(|trait_ref| {
let ident = Ident::new(assoc_item.name, binding.item_name.span);
let item_segment = hir::PathSegment {
ident,
hir_id: binding.hir_id,
res: Res::Err,
args: Some(binding.gen_args),
infer_args: false,
};
self.tcx().mk_alias_ty(assoc_item.def_id, substs_trait_ref_and_assoc_item) let substs_trait_ref_and_assoc_item = self.create_substs_for_associated_item(
}); path_span,
assoc_item.def_id,
&item_segment,
trait_ref.substs,
);
debug!(?substs_trait_ref_and_assoc_item);
self.tcx().mk_alias_ty(assoc_item.def_id, substs_trait_ref_and_assoc_item)
})
};
if !speculative { if !speculative {
// Find any late-bound regions declared in `ty` that are not // Find any late-bound regions declared in `ty` that are not
@ -1206,6 +1253,10 @@ fn add_predicates_for_ast_type_binding(
} }
match binding.kind { match binding.kind {
ConvertedBindingKind::Equality(..) if associated_return_type_bound => {
// TODO: error
todo!()
}
ConvertedBindingKind::Equality(mut term) => { ConvertedBindingKind::Equality(mut term) => {
// "Desugar" a constraint like `T: Iterator<Item = u32>` this to // "Desugar" a constraint like `T: Iterator<Item = u32>` this to
// the "projection predicate" for: // the "projection predicate" for:
@ -1267,7 +1318,7 @@ fn add_predicates_for_ast_type_binding(
// Calling `skip_binder` is okay, because `add_bounds` expects the `param_ty` // Calling `skip_binder` is okay, because `add_bounds` expects the `param_ty`
// parameter to have a skipped binder. // parameter to have a skipped binder.
let param_ty = tcx.mk_alias(ty::Projection, projection_ty.skip_binder()); let param_ty = tcx.mk_alias(ty::Projection, projection_ty.skip_binder());
self.add_bounds(param_ty, ast_bounds.iter(), bounds, candidate.bound_vars()); self.add_bounds(param_ty, ast_bounds.iter(), bounds, projection_ty.bound_vars());
} }
} }
Ok(()) Ok(())
@ -1808,10 +1859,12 @@ fn one_bound_for_assoc_type<I>(
where where
I: Iterator<Item = ty::PolyTraitRef<'tcx>>, I: Iterator<Item = ty::PolyTraitRef<'tcx>>,
{ {
let mut matching_candidates = all_candidates() let mut matching_candidates = all_candidates().filter(|r| {
.filter(|r| self.trait_defines_associated_type_named(r.def_id(), assoc_name)); self.trait_defines_associated_item_named(r.def_id(), ty::AssocKind::Type, assoc_name)
let mut const_candidates = all_candidates() });
.filter(|r| self.trait_defines_associated_const_named(r.def_id(), assoc_name)); let mut const_candidates = all_candidates().filter(|r| {
self.trait_defines_associated_item_named(r.def_id(), ty::AssocKind::Const, assoc_name)
});
let (bound, next_cand) = match (matching_candidates.next(), const_candidates.next()) { let (bound, next_cand) = match (matching_candidates.next(), const_candidates.next()) {
(Some(bound), _) => (bound, matching_candidates.next()), (Some(bound), _) => (bound, matching_candidates.next()),

View File

@ -550,7 +550,11 @@ fn parse_angle_arg(
// Gate associated type bounds, e.g., `Iterator<Item: Ord>`. // Gate associated type bounds, e.g., `Iterator<Item: Ord>`.
if let AssocConstraintKind::Bound { .. } = kind { if let AssocConstraintKind::Bound { .. } = kind {
self.sess.gated_spans.gate(sym::associated_type_bounds, span); if gen_args.as_ref().map_or(false, |args| args.is_parenthesized()) {
self.sess.gated_spans.gate(sym::return_type_notation, span);
} else {
self.sess.gated_spans.gate(sym::associated_type_bounds, span);
}
} }
let constraint = let constraint =
AssocConstraint { id: ast::DUMMY_NODE_ID, ident, gen_args, kind, span }; AssocConstraint { id: ast::DUMMY_NODE_ID, ident, gen_args, kind, span };