Skip to content

Commit

Permalink
Rollup merge of rust-lang#129629 - compiler-errors:rtn-in-path, r=jac…
Browse files Browse the repository at this point in the history
…kh726

Implement Return Type Notation (RTN)'s path form in where clauses

Implement return type notation (RTN) in path position for where clauses. We already had RTN in associated type position ([e.g.](https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021&gist=627a4fb8e2cb334863fbd08ed3722c09)), but per [the RFC](https://rust-lang.github.io/rfcs/3654-return-type-notation.html#where-rtn-can-be-used-for-now):

> As a standalone type, RTN can only be used as the Self type of a where-clause [...]

Specifically, in order to enable code like:

```rust
trait Foo {
    fn bar() -> impl Sized;
}

fn is_send(_: impl Send) {}

fn test<T>()
where
    T: Foo,
    T::bar(..): Send,
{
    is_send(T::bar());
}
```

* In the resolver, when we see a `TyKind::Path` whose final segment is `GenericArgs::ParenthesizedElided` (i.e. `(..)`), resolve that path in the *value* namespace, since we're looking for a method.
* When lowering where clauses in HIR lowering, we first try to intercept an RTN self type via `lower_ty_maybe_return_type_notation`. If we find an RTN type, we lower it manually in a way that respects its higher-ranked-ness (see below) and resolves to the corresponding RPITIT. Anywhere else, we'll emit the same "return type notation not allowed in this position yet" error we do when writing RTN in every other position.
* In `resolve_bound_vars`, we add some special treatment for RTN types in where clauses. Specifically, we need to add new lifetime variables to our binders for the early- and late-bound vars we encounter on the method. This implements the higher-ranked desugaring [laid out in the RFC](https://rust-lang.github.io/rfcs/3654-return-type-notation.html#converting-to-higher-ranked-trait-bounds).

This PR also adds a bunch of tests, mostly negative ones (testing error messages).

In a follow-up PR, I'm going to mark RTN as no longer incomplete, since this PR basically finishes the impl surface that we should initially stabilize, and the RFC was accepted.

cc [RFC 3654](rust-lang/rfcs#3654) and rust-lang#109417
  • Loading branch information
matthiaskrgr authored Sep 21, 2024
2 parents bc8631e + 1de894f commit 7b36e60
Show file tree
Hide file tree
Showing 48 changed files with 1,493 additions and 229 deletions.
5 changes: 3 additions & 2 deletions compiler/rustc_ast_lowering/src/asm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ use super::errors::{
};
use super::LoweringContext;
use crate::{
fluent_generated as fluent, ImplTraitContext, ImplTraitPosition, ParamMode,
ResolverAstLoweringExt,
fluent_generated as fluent, AllowReturnTypeNotation, ImplTraitContext, ImplTraitPosition,
ParamMode, ResolverAstLoweringExt,
};

impl<'a, 'hir> LoweringContext<'a, 'hir> {
Expand Down Expand Up @@ -201,6 +201,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
&sym.qself,
&sym.path,
ParamMode::Optional,
AllowReturnTypeNotation::No,
ImplTraitContext::Disallowed(ImplTraitPosition::Path),
None,
);
Expand Down
3 changes: 2 additions & 1 deletion compiler/rustc_ast_lowering/src/delegation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ use rustc_target::spec::abi;
use {rustc_ast as ast, rustc_hir as hir};

use super::{GenericArgsMode, ImplTraitContext, LoweringContext, ParamMode};
use crate::{ImplTraitPosition, ResolverAstLoweringExt};
use crate::{AllowReturnTypeNotation, ImplTraitPosition, ResolverAstLoweringExt};

pub(crate) struct DelegationResults<'hir> {
pub body_id: hir::BodyId,
Expand Down Expand Up @@ -340,6 +340,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
&delegation.qself,
&delegation.path,
ParamMode::Optional,
AllowReturnTypeNotation::No,
ImplTraitContext::Disallowed(ImplTraitPosition::Path),
None,
);
Expand Down
7 changes: 6 additions & 1 deletion compiler/rustc_ast_lowering/src/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ use super::{
GenericArgsMode, ImplTraitContext, LoweringContext, ParamMode, ResolverAstLoweringExt,
};
use crate::errors::YieldInClosure;
use crate::{fluent_generated, FnDeclKind, ImplTraitPosition};
use crate::{fluent_generated, AllowReturnTypeNotation, FnDeclKind, ImplTraitPosition};

impl<'hir> LoweringContext<'_, 'hir> {
fn lower_exprs(&mut self, exprs: &[AstP<Expr>]) -> &'hir [hir::Expr<'hir>] {
Expand Down Expand Up @@ -281,6 +281,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
qself,
path,
ParamMode::Optional,
AllowReturnTypeNotation::No,
ImplTraitContext::Disallowed(ImplTraitPosition::Path),
None,
);
Expand Down Expand Up @@ -328,6 +329,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
&se.qself,
&se.path,
ParamMode::Optional,
AllowReturnTypeNotation::No,
ImplTraitContext::Disallowed(ImplTraitPosition::Path),
None,
)),
Expand Down Expand Up @@ -1291,6 +1293,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
qself,
path,
ParamMode::Optional,
AllowReturnTypeNotation::No,
ImplTraitContext::Disallowed(ImplTraitPosition::Path),
None,
);
Expand All @@ -1311,6 +1314,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
qself,
path,
ParamMode::Optional,
AllowReturnTypeNotation::No,
ImplTraitContext::Disallowed(ImplTraitPosition::Path),
None,
);
Expand All @@ -1336,6 +1340,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
&se.qself,
&se.path,
ParamMode::Optional,
AllowReturnTypeNotation::No,
ImplTraitContext::Disallowed(ImplTraitPosition::Path),
None,
);
Expand Down
27 changes: 26 additions & 1 deletion compiler/rustc_ast_lowering/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -485,9 +485,23 @@ enum ParamMode {
Optional,
}

#[derive(Copy, Clone, Debug)]
enum AllowReturnTypeNotation {
/// Only in types, since RTN is denied later during HIR lowering.
Yes,
/// All other positions (path expr, method, use tree).
No,
}

enum GenericArgsMode {
/// Allow paren sugar, don't allow RTN.
ParenSugar,
/// Allow RTN, don't allow paren sugar.
ReturnTypeNotation,
// Error if parenthesized generics or RTN are encountered.
Err,
/// Silence errors when lowering generics. Only used with `Res::Err`.
Silence,
}

impl<'a, 'hir> LoweringContext<'a, 'hir> {
Expand Down Expand Up @@ -1226,7 +1240,15 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
}

let id = self.lower_node_id(t.id);
let qpath = self.lower_qpath(t.id, qself, path, param_mode, itctx, None);
let qpath = self.lower_qpath(
t.id,
qself,
path,
param_mode,
AllowReturnTypeNotation::Yes,
itctx,
None,
);
self.ty_path(id, t.span, qpath)
}

Expand Down Expand Up @@ -2203,6 +2225,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
&None,
&p.path,
ParamMode::Explicit,
AllowReturnTypeNotation::No,
itctx,
Some(modifiers),
) {
Expand Down Expand Up @@ -2341,6 +2364,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
&None,
path,
ParamMode::Optional,
AllowReturnTypeNotation::No,
ImplTraitContext::Disallowed(ImplTraitPosition::Path),
None,
);
Expand Down Expand Up @@ -2419,6 +2443,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
qself,
path,
ParamMode::Optional,
AllowReturnTypeNotation::No,
ImplTraitContext::Disallowed(ImplTraitPosition::Path),
None,
);
Expand Down
5 changes: 4 additions & 1 deletion compiler/rustc_ast_lowering/src/pat.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use super::errors::{
ArbitraryExpressionInPattern, ExtraDoubleDot, MisplacedDoubleDot, SubTupleBinding,
};
use super::{ImplTraitContext, LoweringContext, ParamMode, ResolverAstLoweringExt};
use crate::ImplTraitPosition;
use crate::{AllowReturnTypeNotation, ImplTraitPosition};

impl<'a, 'hir> LoweringContext<'a, 'hir> {
pub(crate) fn lower_pat(&mut self, pattern: &Pat) -> &'hir hir::Pat<'hir> {
Expand All @@ -38,6 +38,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
qself,
path,
ParamMode::Optional,
AllowReturnTypeNotation::No,
ImplTraitContext::Disallowed(ImplTraitPosition::Path),
None,
);
Expand All @@ -55,6 +56,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
qself,
path,
ParamMode::Optional,
AllowReturnTypeNotation::No,
ImplTraitContext::Disallowed(ImplTraitPosition::Path),
None,
);
Expand All @@ -66,6 +68,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
qself,
path,
ParamMode::Optional,
AllowReturnTypeNotation::No,
ImplTraitContext::Disallowed(ImplTraitPosition::Path),
None,
);
Expand Down
80 changes: 69 additions & 11 deletions compiler/rustc_ast_lowering/src/path.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use rustc_hir::def::{DefKind, PartialRes, Res};
use rustc_hir::def_id::DefId;
use rustc_hir::GenericArg;
use rustc_middle::span_bug;
use rustc_session::parse::add_feature_diagnostics;
use rustc_span::symbol::{kw, sym, Ident};
use rustc_span::{BytePos, DesugaringKind, Span, Symbol, DUMMY_SP};
use smallvec::{smallvec, SmallVec};
Expand All @@ -15,10 +16,9 @@ use super::errors::{
GenericTypeWithParentheses, UseAngleBrackets,
};
use super::{
GenericArgsCtor, GenericArgsMode, ImplTraitContext, LifetimeRes, LoweringContext, ParamMode,
ResolverAstLoweringExt,
AllowReturnTypeNotation, GenericArgsCtor, GenericArgsMode, ImplTraitContext, ImplTraitPosition,
LifetimeRes, LoweringContext, ParamMode, ResolverAstLoweringExt,
};
use crate::ImplTraitPosition;

impl<'a, 'hir> LoweringContext<'a, 'hir> {
#[instrument(level = "trace", skip(self))]
Expand All @@ -28,6 +28,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
qself: &Option<ptr::P<QSelf>>,
p: &Path,
param_mode: ParamMode,
allow_return_type_notation: AllowReturnTypeNotation,
itctx: ImplTraitContext,
// modifiers of the impl/bound if this is a trait path
modifiers: Option<ast::TraitBoundModifiers>,
Expand Down Expand Up @@ -103,8 +104,14 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
{
GenericArgsMode::ParenSugar
}
Res::Def(DefKind::AssocFn, _) if i + 1 == proj_start => {
match allow_return_type_notation {
AllowReturnTypeNotation::Yes => GenericArgsMode::ReturnTypeNotation,
AllowReturnTypeNotation::No => GenericArgsMode::Err,
}
}
// Avoid duplicated errors.
Res::Err => GenericArgsMode::ParenSugar,
Res::Err => GenericArgsMode::Silence,
// An error
_ => GenericArgsMode::Err,
};
Expand Down Expand Up @@ -164,11 +171,20 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
// 3. `<<std::vec::Vec<T>>::IntoIter>::Item`
// * final path is `<<<std::vec::Vec<T>>::IntoIter>::Item>::clone`
for (i, segment) in p.segments.iter().enumerate().skip(proj_start) {
// If this is a type-dependent `T::method(..)`.
let generic_args_mode = if i + 1 == p.segments.len()
&& matches!(allow_return_type_notation, AllowReturnTypeNotation::Yes)
{
GenericArgsMode::ReturnTypeNotation
} else {
GenericArgsMode::Err
};

let hir_segment = self.arena.alloc(self.lower_path_segment(
p.span,
segment,
param_mode,
GenericArgsMode::Err,
generic_args_mode,
itctx,
None,
));
Expand Down Expand Up @@ -238,11 +254,46 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
self.lower_angle_bracketed_parameter_data(data, param_mode, itctx)
}
GenericArgs::Parenthesized(data) => match generic_args_mode {
GenericArgsMode::ParenSugar => self.lower_parenthesized_parameter_data(
data,
itctx,
bound_modifier_allowed_features,
),
GenericArgsMode::ReturnTypeNotation => {
let mut err = if !data.inputs.is_empty() {
self.dcx().create_err(BadReturnTypeNotation::Inputs {
span: data.inputs_span,
})
} else if let FnRetTy::Ty(ty) = &data.output {
self.dcx().create_err(BadReturnTypeNotation::Output {
span: data.inputs_span.shrink_to_hi().to(ty.span),
})
} else {
self.dcx().create_err(BadReturnTypeNotation::NeedsDots {
span: data.inputs_span,
})
};
if !self.tcx.features().return_type_notation
&& self.tcx.sess.is_nightly_build()
{
add_feature_diagnostics(
&mut err,
&self.tcx.sess,
sym::return_type_notation,
);
}
err.emit();
(
GenericArgsCtor {
args: Default::default(),
constraints: &[],
parenthesized: hir::GenericArgsParentheses::ReturnTypeNotation,
span: path_span,
},
false,
)
}
GenericArgsMode::ParenSugar | GenericArgsMode::Silence => self
.lower_parenthesized_parameter_data(
data,
itctx,
bound_modifier_allowed_features,
),
GenericArgsMode::Err => {
// Suggest replacing parentheses with angle brackets `Trait(params...)` to `Trait<params...>`
let sub = if !data.inputs.is_empty() {
Expand Down Expand Up @@ -279,7 +330,14 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
}
},
GenericArgs::ParenthesizedElided(span) => {
self.dcx().emit_err(BadReturnTypeNotation::Position { span: *span });
match generic_args_mode {
GenericArgsMode::ReturnTypeNotation | GenericArgsMode::Silence => {
// Ok
}
GenericArgsMode::ParenSugar | GenericArgsMode::Err => {
self.dcx().emit_err(BadReturnTypeNotation::Position { span: *span });
}
}
(
GenericArgsCtor {
args: Default::default(),
Expand Down
4 changes: 3 additions & 1 deletion compiler/rustc_hir_analysis/messages.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ hir_analysis_assoc_kind_mismatch = expected {$expected}, found {$got}
hir_analysis_assoc_kind_mismatch_wrap_in_braces_sugg = consider adding braces here
hir_analysis_associated_type_trait_uninferred_generic_params = cannot use the associated type of a trait with uninferred generic parameters
hir_analysis_associated_type_trait_uninferred_generic_params = cannot use the associated {$what} of a trait with uninferred generic parameters
.suggestion = use a fully qualified path with inferred lifetimes
hir_analysis_associated_type_trait_uninferred_generic_params_multipart_suggestion = use a fully qualified path with explicit lifetimes
Expand All @@ -48,6 +48,8 @@ hir_analysis_auto_deref_reached_recursion_limit = reached the recursion limit wh
hir_analysis_bad_precise_capture = expected {$kind} parameter in `use<...>` precise captures list, found {$found}
hir_analysis_bad_return_type_notation_position = return type notation not allowed in this position yet
hir_analysis_cannot_capture_late_bound_const =
cannot capture late-bound const parameter in {$what}
.label = parameter defined here
Expand Down
5 changes: 3 additions & 2 deletions compiler/rustc_hir_analysis/src/collect.rs
Original file line number Diff line number Diff line change
Expand Up @@ -460,7 +460,7 @@ impl<'tcx> HirTyLowerer<'tcx> for ItemCtxt<'tcx> {
[] => (generics.span, format!("<{lt_name}>")),
[bound, ..] => (bound.span.shrink_to_lo(), format!("{lt_name}, ")),
};
mpart_sugg = Some(errors::AssociatedTypeTraitUninferredGenericParamsMultipartSuggestion {
mpart_sugg = Some(errors::AssociatedItemTraitUninferredGenericParamsMultipartSuggestion {
fspan: lt_sp,
first: sugg,
sspan: span.with_hi(item_segment.ident.span.lo()),
Expand Down Expand Up @@ -502,11 +502,12 @@ impl<'tcx> HirTyLowerer<'tcx> for ItemCtxt<'tcx> {
}
Ty::new_error(
self.tcx(),
self.tcx().dcx().emit_err(errors::AssociatedTypeTraitUninferredGenericParams {
self.tcx().dcx().emit_err(errors::AssociatedItemTraitUninferredGenericParams {
span,
inferred_sugg,
bound,
mpart_sugg,
what: "type",
}),
)
}
Expand Down
13 changes: 7 additions & 6 deletions compiler/rustc_hir_analysis/src/collect/predicates_of.rs
Original file line number Diff line number Diff line change
Expand Up @@ -240,7 +240,8 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen
for predicate in hir_generics.predicates {
match predicate {
hir::WherePredicate::BoundPredicate(bound_pred) => {
let ty = icx.lower_ty(bound_pred.bounded_ty);
let ty = icx.lowerer().lower_ty_maybe_return_type_notation(bound_pred.bounded_ty);

let bound_vars = tcx.late_bound_vars(bound_pred.hir_id);
// Keep the type around in a dummy predicate, in case of no bounds.
// That way, `where Ty:` is not a complete noop (see #53696) and `Ty`
Expand Down Expand Up @@ -770,6 +771,10 @@ impl<'tcx> ItemCtxt<'tcx> {
continue;
};

// Subtle: If we're collecting `SelfAndAssociatedTypeBounds`, then we
// want to only consider predicates with `Self: ...`, but we don't want
// `OnlySelfBounds(true)` since we want to collect the nested associated
// type bound as well.
let (only_self_bounds, assoc_name) = match filter {
PredicateFilter::All | PredicateFilter::SelfAndAssociatedTypeBounds => {
(OnlySelfBounds(false), None)
Expand All @@ -780,14 +785,10 @@ impl<'tcx> ItemCtxt<'tcx> {
}
};

// Subtle: If we're collecting `SelfAndAssociatedTypeBounds`, then we
// want to only consider predicates with `Self: ...`, but we don't want
// `OnlySelfBounds(true)` since we want to collect the nested associated
// type bound as well.
let bound_ty = if predicate.is_param_bound(param_def_id.to_def_id()) {
ty
} else if matches!(filter, PredicateFilter::All) {
self.lower_ty(predicate.bounded_ty)
self.lowerer().lower_ty_maybe_return_type_notation(predicate.bounded_ty)
} else {
continue;
};
Expand Down
Loading

0 comments on commit 7b36e60

Please sign in to comment.