Skip to content

Commit ae3d610

Browse files
Flesh out some TODOs
1 parent d88cef7 commit ae3d610

File tree

7 files changed

+96
-18
lines changed

7 files changed

+96
-18
lines changed

compiler/rustc_hir_analysis/messages.ftl

+1-1
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ hir_analysis_assoc_kind_mismatch = expected {$expected}, found {$got}
3737
3838
hir_analysis_assoc_kind_mismatch_wrap_in_braces_sugg = consider adding braces here
3939
40-
hir_analysis_associated_type_trait_uninferred_generic_params = cannot use the associated type of a trait with uninferred generic parameters
40+
hir_analysis_associated_type_trait_uninferred_generic_params = cannot use the associated {$what} of a trait with uninferred generic parameters
4141
.suggestion = use a fully qualified path with inferred lifetimes
4242
4343
hir_analysis_associated_type_trait_uninferred_generic_params_multipart_suggestion = use a fully qualified path with explicit lifetimes

compiler/rustc_hir_analysis/src/collect.rs

+1
Original file line numberDiff line numberDiff line change
@@ -507,6 +507,7 @@ impl<'tcx> HirTyLowerer<'tcx> for ItemCtxt<'tcx> {
507507
inferred_sugg,
508508
bound,
509509
mpart_sugg,
510+
what: "type",
510511
}),
511512
)
512513
}

compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs

+40-8
Original file line numberDiff line numberDiff line change
@@ -1862,19 +1862,38 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
18621862
assert_eq!(old_value, Some(bad_def));
18631863
}
18641864

1865-
// TODO:
1865+
// When we have a return type notation type in a where clause, like
1866+
// `where <T as Trait>::method(..): Send`, we need to introduce new bound
1867+
// vars to the existing where clause's binder, to represent the lifetimes
1868+
// elided by the return-type-notation syntax.
1869+
//
1870+
// For example, given
1871+
// ```
1872+
// trait Foo {
1873+
// async fn x<'r, T>();
1874+
// }
1875+
// ```
1876+
// and a bound that looks like:
1877+
// `for<'a, 'b> <T as Trait<'a>>::x(): Other<'b>`
1878+
// this is going to expand to something like:
1879+
// `for<'a, 'b, 'r, T> <T as Trait<'a>>::x::<'r, T>::{opaque#0}: Other<'b>`.
1880+
//
1881+
// We handle this similarly for associated-type-bound style return-type-notation
1882+
// in `visit_segment_args`.
18661883
fn try_append_return_type_notation_params(
18671884
&mut self,
18681885
hir_id: HirId,
18691886
hir_ty: &'tcx hir::Ty<'tcx>,
18701887
) {
18711888
let hir::TyKind::Path(qpath) = hir_ty.kind else {
1872-
// TODO:
1889+
// We only care about path types here. All other self types
1890+
// (including nesting the RTN type in another type) don't do
1891+
// anything.
18731892
return;
18741893
};
18751894

18761895
let (mut bound_vars, item_def_id, item_segment) = match qpath {
1877-
// TODO:
1896+
// If we have a fully qualified method, then we don't need to do any special lookup.
18781897
hir::QPath::Resolved(_, path)
18791898
if let [.., item_segment] = &path.segments[..]
18801899
&& item_segment.args.is_some_and(|args| {
@@ -1890,23 +1909,32 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
18901909
(vec![], item_def_id, item_segment)
18911910
}
18921911

1893-
// TODO:
1912+
// If we have a type-dependent path, then we do need to do some lookup.
18941913
hir::QPath::TypeRelative(qself, item_segment)
18951914
if item_segment.args.is_some_and(|args| {
18961915
matches!(args.parenthesized, hir::GenericArgsParentheses::ReturnTypeNotation)
18971916
}) =>
18981917
{
1918+
// First, ignore a qself that isn't a type or `Self` param. Those are the
1919+
// only ones that support `T::Assoc` anyways in HIR lowering.
18991920
let hir::TyKind::Path(hir::QPath::Resolved(None, path)) = qself.kind else {
19001921
return;
19011922
};
1902-
19031923
match path.res {
19041924
Res::Def(DefKind::TyParam, _) | Res::SelfTyParam { trait_: _ } => {
1925+
// Get the generics of this type's hir owner. This is *different*
1926+
// from the generics of the parameter's definition, since we want
1927+
// to be able to resolve an RTN path on a nested body (e.g. method
1928+
// inside an impl) using the where clauses on the method.
19051929
let Some(generics) = self.tcx.hir_owner_node(hir_id.owner).generics()
19061930
else {
19071931
return;
19081932
};
19091933

1934+
// Look for the first bound that contains an associated type that
1935+
// matches the segment that we're looking for. We ignore any subsequent
1936+
// bounds since we'll be emitting a hard error in HIR lowering, so this
1937+
// is purely speculative.
19101938
let one_bound = generics.predicates.iter().find_map(|predicate| {
19111939
let hir::WherePredicate::BoundPredicate(predicate) = predicate else {
19121940
return None;
@@ -1944,7 +1972,9 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
19441972
_ => return,
19451973
};
19461974

1947-
// TODO:
1975+
// Append the early-bound vars on the function, and then the late-bound ones.
1976+
// We actually turn type parameters into higher-ranked types here, but we
1977+
// deny them later in HIR lowering.
19481978
bound_vars.extend(self.tcx.generics_of(item_def_id).own_params.iter().map(|param| {
19491979
match param.kind {
19501980
ty::GenericParamDefKind::Lifetime => ty::BoundVariableKind::Region(
@@ -1958,11 +1988,13 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
19581988
}));
19591989
bound_vars.extend(self.tcx.fn_sig(item_def_id).instantiate_identity().bound_vars());
19601990

1961-
// TODO:
1991+
// SUBTLE: Stash the old bound vars onto the *item segment* before appending
1992+
// the new bound vars. We do this because we need to know how many bound vars
1993+
// are present on the binder explicitly (i.e. not return-type-notation vars)
1994+
// to do bound var shifting correctly in HIR lowering.
19621995
let existing_bound_vars = self.map.late_bound_vars.get_mut(&hir_id).unwrap();
19631996
let existing_bound_vars_saved = existing_bound_vars.clone();
19641997
existing_bound_vars.extend(bound_vars);
1965-
// TODO: subtle
19661998
self.record_late_bound_vars(item_segment.hir_id, existing_bound_vars_saved);
19671999
}
19682000
}

compiler/rustc_hir_analysis/src/errors.rs

+1
Original file line numberDiff line numberDiff line change
@@ -788,6 +788,7 @@ pub(crate) struct AssociatedTypeTraitUninferredGenericParams {
788788
pub bound: String,
789789
#[subdiagnostic]
790790
pub mpart_sugg: Option<AssociatedTypeTraitUninferredGenericParamsMultipartSuggestion>,
791+
pub what: &'static str,
791792
}
792793

793794
#[derive(Subdiagnostic)]

compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs

+36-7
Original file line numberDiff line numberDiff line change
@@ -464,7 +464,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
464464
Ok(())
465465
}
466466

467-
// TODO:
467+
/// Lower a type, possibly specially handling the type if it's a return type notation
468+
/// which we otherwise deny in other positions.
468469
pub fn lower_ty_maybe_return_type_notation(&self, hir_ty: &hir::Ty<'tcx>) -> Ty<'tcx> {
469470
let hir::TyKind::Path(qpath) = hir_ty.kind else {
470471
return self.lower_ty(hir_ty);
@@ -481,14 +482,16 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
481482
)
482483
}) =>
483484
{
485+
// We don't allow generics on the module segments.
484486
let _ =
485487
self.prohibit_generic_args(mod_segments.iter(), GenericsArgsErrExtend::None);
486488

487489
let Res::Def(DefKind::AssocFn, item_def_id) = path.res else {
488-
bug!();
490+
bug!("expected RTN to resolve to associated fn");
489491
};
490492
let trait_def_id = tcx.parent(item_def_id);
491493

494+
// Good error for `where Trait::method(..): Send`.
492495
let Some(self_ty) = opt_self_ty else {
493496
return self.error_missing_qpath_self_ty(
494497
trait_def_id,
@@ -507,6 +510,18 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
507510
ty::BoundConstness::NotConst,
508511
);
509512

513+
// SUBTLE: As noted at the end of `try_append_return_type_notation_params`
514+
// in `resolve_bound_vars`, we stash the explicit bound vars of the where
515+
// clause onto the item segment of the RTN type. This allows us to know
516+
// how many bound vars are *not* coming from the signature of the function
517+
// from lowering RTN itself.
518+
//
519+
// For example, in `where for<'a> <T as Trait<'a>>::method(..): Other`,
520+
// the `late_bound_vars` of the where clause predicate (i.e. this HIR ty's
521+
// parent) will include `'a` AND all the early- and late-bound vars of the
522+
// method. But when lowering the RTN type, we just want the list of vars
523+
// we used to resolve the trait ref. We explicitly stored those back onto
524+
// the item segment, since there's no other good place to put them.
510525
let candidate =
511526
ty::Binder::bind_with_vars(trait_ref, tcx.late_bound_vars(item_segment.hir_id));
512527

@@ -538,7 +553,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
538553
}
539554
}
540555

541-
// TODO:
556+
/// Perform type-dependent lookup for a *method* for return type notation.
557+
/// This generally mirrors `<dyn HirTyLowerer>::lower_assoc_path`.
542558
fn resolve_type_relative_return_type_notation(
543559
&self,
544560
qself: &'tcx hir::Ty<'tcx>,
@@ -591,12 +607,22 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
591607
_ => todo!(),
592608
};
593609

594-
// Don't let `T::method` resolve to some `for<'a> <T as Tr<'a>>::method`.
610+
// Don't let `T::method` resolve to some `for<'a> <T as Tr<'a>>::method`,
611+
// which may happen via a higher-ranked where clause or supertrait.
595612
// This is the same restrictions as associated types; even though we could
596613
// support it, it just makes things a lot more difficult to support in
597-
// `resolve_bound_vars`.
614+
// `resolve_bound_vars`, since we'd need to introduce those as elided
615+
// bound vars on the where clause too.
598616
if bound.has_bound_vars() {
599-
todo!();
617+
return Err(self.tcx().dcx().emit_err(
618+
errors::AssociatedTypeTraitUninferredGenericParams {
619+
span,
620+
inferred_sugg: Some(span.with_hi(item_segment.ident.span.lo())),
621+
bound: format!("{}::", tcx.anonymize_bound_vars(bound).skip_binder(),),
622+
mpart_sugg: None,
623+
what: "function",
624+
},
625+
));
600626
}
601627

602628
let trait_def_id = bound.def_id();
@@ -607,7 +633,10 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
607633
Ok((bound, assoc_ty.def_id))
608634
}
609635

610-
// TODO:
636+
/// Do the common parts of lowering an RTN type. This involves extending the
637+
/// candidate binder to include all of the early- and late-bound vars that are
638+
/// defined on the function itself, and constructing a projection to the RPITIT
639+
/// return type of that function.
611640
fn lower_return_type_notation_ty(
612641
&self,
613642
candidate: ty::PolyTraitRef<'tcx>,

compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs

+14-1
Original file line numberDiff line numberDiff line change
@@ -2070,6 +2070,17 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
20702070
};
20712071
self.lower_trait_object_ty(hir_ty.span, hir_ty.hir_id, bounds, lifetime, repr)
20722072
}
2073+
// If we encounter a fully qualified path with RTN generics, then it must have
2074+
// *not* gone through `lower_ty_maybe_return_type_notation`, and therefore
2075+
// it's certainly in an illegal position.
2076+
hir::TyKind::Path(hir::QPath::Resolved(_, path))
2077+
if path.segments.last().and_then(|segment| segment.args).is_some_and(|args| {
2078+
matches!(args.parenthesized, hir::GenericArgsParentheses::ReturnTypeNotation)
2079+
}) =>
2080+
{
2081+
let guar = self.dcx().emit_err(BadReturnTypeNotation { span: hir_ty.span });
2082+
Ty::new_error(tcx, guar)
2083+
}
20732084
hir::TyKind::Path(hir::QPath::Resolved(maybe_qself, path)) => {
20742085
debug!(?maybe_qself, ?path);
20752086
let opt_self_ty = maybe_qself.as_ref().map(|qself| self.lower_ty(qself));
@@ -2094,7 +2105,9 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
20942105
ref i => bug!("`impl Trait` pointed to non-opaque type?? {:#?}", i),
20952106
}
20962107
}
2097-
// TODO:
2108+
// If we encounter a type relative path with RTN generics, then it must have
2109+
// *not* gone through `lower_ty_maybe_return_type_notation`, and therefore
2110+
// it's certainly in an illegal position.
20982111
hir::TyKind::Path(hir::QPath::TypeRelative(_, segment))
20992112
if segment.args.is_some_and(|args| {
21002113
matches!(args.parenthesized, hir::GenericArgsParentheses::ReturnTypeNotation)

compiler/rustc_resolve/src/late.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -772,7 +772,9 @@ impl<'a: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast,
772772
TyKind::Path(qself, path) => {
773773
self.diag_metadata.current_type_path = Some(ty);
774774

775-
// TODO:
775+
// If we have a path that ends with `(..)`, then it must be
776+
// return type notation. Resolve that path in the *value*
777+
// namespace.
776778
let source = if let Some(seg) = path.segments.last()
777779
&& let Some(args) = &seg.args
778780
&& matches!(**args, GenericArgs::ParenthesizedElided(..))

0 commit comments

Comments
 (0)