Rollup merge of #129629 - compiler-errors:rtn-in-path, r=jackh726
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](https://github.com/rust-lang/rfcs/pull/3654) and https://github.com/rust-lang/rust/issues/109417
This commit is contained in:
commit
d72d44d8ed
48 changed files with 1493 additions and 229 deletions
|
@ -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> {
|
||||
|
@ -201,6 +201,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
&sym.qself,
|
||||
&sym.path,
|
||||
ParamMode::Optional,
|
||||
AllowReturnTypeNotation::No,
|
||||
ImplTraitContext::Disallowed(ImplTraitPosition::Path),
|
||||
None,
|
||||
);
|
||||
|
|
|
@ -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,
|
||||
|
@ -340,6 +340,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
&delegation.qself,
|
||||
&delegation.path,
|
||||
ParamMode::Optional,
|
||||
AllowReturnTypeNotation::No,
|
||||
ImplTraitContext::Disallowed(ImplTraitPosition::Path),
|
||||
None,
|
||||
);
|
||||
|
|
|
@ -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>] {
|
||||
|
@ -281,6 +281,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
qself,
|
||||
path,
|
||||
ParamMode::Optional,
|
||||
AllowReturnTypeNotation::No,
|
||||
ImplTraitContext::Disallowed(ImplTraitPosition::Path),
|
||||
None,
|
||||
);
|
||||
|
@ -328,6 +329,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
&se.qself,
|
||||
&se.path,
|
||||
ParamMode::Optional,
|
||||
AllowReturnTypeNotation::No,
|
||||
ImplTraitContext::Disallowed(ImplTraitPosition::Path),
|
||||
None,
|
||||
)),
|
||||
|
@ -1291,6 +1293,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
qself,
|
||||
path,
|
||||
ParamMode::Optional,
|
||||
AllowReturnTypeNotation::No,
|
||||
ImplTraitContext::Disallowed(ImplTraitPosition::Path),
|
||||
None,
|
||||
);
|
||||
|
@ -1311,6 +1314,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
qself,
|
||||
path,
|
||||
ParamMode::Optional,
|
||||
AllowReturnTypeNotation::No,
|
||||
ImplTraitContext::Disallowed(ImplTraitPosition::Path),
|
||||
None,
|
||||
);
|
||||
|
@ -1336,6 +1340,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
&se.qself,
|
||||
&se.path,
|
||||
ParamMode::Optional,
|
||||
AllowReturnTypeNotation::No,
|
||||
ImplTraitContext::Disallowed(ImplTraitPosition::Path),
|
||||
None,
|
||||
);
|
||||
|
|
|
@ -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> {
|
||||
|
@ -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)
|
||||
}
|
||||
|
||||
|
@ -2203,6 +2225,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
&None,
|
||||
&p.path,
|
||||
ParamMode::Explicit,
|
||||
AllowReturnTypeNotation::No,
|
||||
itctx,
|
||||
Some(modifiers),
|
||||
) {
|
||||
|
@ -2341,6 +2364,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
&None,
|
||||
path,
|
||||
ParamMode::Optional,
|
||||
AllowReturnTypeNotation::No,
|
||||
ImplTraitContext::Disallowed(ImplTraitPosition::Path),
|
||||
None,
|
||||
);
|
||||
|
@ -2419,6 +2443,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
qself,
|
||||
path,
|
||||
ParamMode::Optional,
|
||||
AllowReturnTypeNotation::No,
|
||||
ImplTraitContext::Disallowed(ImplTraitPosition::Path),
|
||||
None,
|
||||
);
|
||||
|
|
|
@ -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> {
|
||||
|
@ -38,6 +38,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
qself,
|
||||
path,
|
||||
ParamMode::Optional,
|
||||
AllowReturnTypeNotation::No,
|
||||
ImplTraitContext::Disallowed(ImplTraitPosition::Path),
|
||||
None,
|
||||
);
|
||||
|
@ -55,6 +56,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
qself,
|
||||
path,
|
||||
ParamMode::Optional,
|
||||
AllowReturnTypeNotation::No,
|
||||
ImplTraitContext::Disallowed(ImplTraitPosition::Path),
|
||||
None,
|
||||
);
|
||||
|
@ -66,6 +68,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
qself,
|
||||
path,
|
||||
ParamMode::Optional,
|
||||
AllowReturnTypeNotation::No,
|
||||
ImplTraitContext::Disallowed(ImplTraitPosition::Path),
|
||||
None,
|
||||
);
|
||||
|
|
|
@ -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};
|
||||
|
@ -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))]
|
||||
|
@ -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>,
|
||||
|
@ -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,
|
||||
};
|
||||
|
@ -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,
|
||||
));
|
||||
|
@ -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() {
|
||||
|
@ -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(),
|
||||
|
|
|
@ -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
|
||||
|
@ -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
|
||||
|
|
|
@ -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()),
|
||||
|
@ -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",
|
||||
}),
|
||||
)
|
||||
}
|
||||
|
|
|
@ -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`
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -889,7 +889,12 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
|
|||
(pair, r)
|
||||
})
|
||||
.unzip();
|
||||
|
||||
self.record_late_bound_vars(hir_id, binders);
|
||||
|
||||
// If this is an RTN type in the self type, then append those to the binder.
|
||||
self.try_append_return_type_notation_params(hir_id, bounded_ty);
|
||||
|
||||
// Even if there are no lifetimes defined here, we still wrap it in a binder
|
||||
// scope. If there happens to be a nested poly trait ref (an error), that
|
||||
// will be `Concatenating` anyways, so we don't have to worry about the depth
|
||||
|
@ -1635,9 +1640,9 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
|
|||
// }
|
||||
// ```
|
||||
// and a bound that looks like:
|
||||
// `for<'a> T::Trait<'a, x(): for<'b> Other<'b>>`
|
||||
// `for<'a> T::Trait<'a, x(..): for<'b> Other<'b>>`
|
||||
// this is going to expand to something like:
|
||||
// `for<'a> for<'r, T> <T as Trait<'a>>::x::<'r, T>::{opaque#0}: for<'b> Other<'b>`.
|
||||
// `for<'a> for<'r> <T as Trait<'a>>::x::<'r, T>::{opaque#0}: for<'b> Other<'b>`.
|
||||
if constraint.gen_args.parenthesized == hir::GenericArgsParentheses::ReturnTypeNotation
|
||||
{
|
||||
let bound_vars = if let Some(type_def_id) = type_def_id
|
||||
|
@ -1839,6 +1844,178 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
|
|||
let old_value = self.map.defs.swap_remove(&lifetime_ref.hir_id);
|
||||
assert_eq!(old_value, Some(bad_def));
|
||||
}
|
||||
|
||||
// When we have a return type notation type in a where clause, like
|
||||
// `where <T as Trait>::method(..): Send`, we need to introduce new bound
|
||||
// vars to the existing where clause's binder, to represent the lifetimes
|
||||
// elided by the return-type-notation syntax.
|
||||
//
|
||||
// For example, given
|
||||
// ```
|
||||
// trait Foo {
|
||||
// async fn x<'r>();
|
||||
// }
|
||||
// ```
|
||||
// and a bound that looks like:
|
||||
// `for<'a, 'b> <T as Trait<'a>>::x(): Other<'b>`
|
||||
// this is going to expand to something like:
|
||||
// `for<'a, 'b, 'r> <T as Trait<'a>>::x::<'r, T>::{opaque#0}: Other<'b>`.
|
||||
//
|
||||
// We handle this similarly for associated-type-bound style return-type-notation
|
||||
// in `visit_segment_args`.
|
||||
fn try_append_return_type_notation_params(
|
||||
&mut self,
|
||||
hir_id: HirId,
|
||||
hir_ty: &'tcx hir::Ty<'tcx>,
|
||||
) {
|
||||
let hir::TyKind::Path(qpath) = hir_ty.kind else {
|
||||
// We only care about path types here. All other self types
|
||||
// (including nesting the RTN type in another type) don't do
|
||||
// anything.
|
||||
return;
|
||||
};
|
||||
|
||||
let (mut bound_vars, item_def_id, item_segment) = match qpath {
|
||||
// If we have a fully qualified method, then we don't need to do any special lookup.
|
||||
hir::QPath::Resolved(_, path)
|
||||
if let [.., item_segment] = &path.segments[..]
|
||||
&& item_segment.args.is_some_and(|args| {
|
||||
matches!(
|
||||
args.parenthesized,
|
||||
hir::GenericArgsParentheses::ReturnTypeNotation
|
||||
)
|
||||
}) =>
|
||||
{
|
||||
match path.res {
|
||||
Res::Err => return,
|
||||
Res::Def(DefKind::AssocFn, item_def_id) => (vec![], item_def_id, item_segment),
|
||||
_ => bug!("only expected method resolution for fully qualified RTN"),
|
||||
}
|
||||
}
|
||||
|
||||
// If we have a type-dependent path, then we do need to do some lookup.
|
||||
hir::QPath::TypeRelative(qself, item_segment)
|
||||
if item_segment.args.is_some_and(|args| {
|
||||
matches!(args.parenthesized, hir::GenericArgsParentheses::ReturnTypeNotation)
|
||||
}) =>
|
||||
{
|
||||
// First, ignore a qself that isn't a type or `Self` param. Those are the
|
||||
// only ones that support `T::Assoc` anyways in HIR lowering.
|
||||
let hir::TyKind::Path(hir::QPath::Resolved(None, path)) = qself.kind else {
|
||||
return;
|
||||
};
|
||||
match path.res {
|
||||
Res::Def(DefKind::TyParam, _) | Res::SelfTyParam { trait_: _ } => {
|
||||
// Get the generics of this type's hir owner. This is *different*
|
||||
// from the generics of the parameter's definition, since we want
|
||||
// to be able to resolve an RTN path on a nested body (e.g. method
|
||||
// inside an impl) using the where clauses on the method.
|
||||
// FIXME(return_type_notation): Think of some better way of doing this.
|
||||
let Some(generics) = self.tcx.hir_owner_node(hir_id.owner).generics()
|
||||
else {
|
||||
return;
|
||||
};
|
||||
|
||||
// Look for the first bound that contains an associated type that
|
||||
// matches the segment that we're looking for. We ignore any subsequent
|
||||
// bounds since we'll be emitting a hard error in HIR lowering, so this
|
||||
// is purely speculative.
|
||||
let one_bound = generics.predicates.iter().find_map(|predicate| {
|
||||
let hir::WherePredicate::BoundPredicate(predicate) = predicate else {
|
||||
return None;
|
||||
};
|
||||
let hir::TyKind::Path(hir::QPath::Resolved(None, bounded_path)) =
|
||||
predicate.bounded_ty.kind
|
||||
else {
|
||||
return None;
|
||||
};
|
||||
if bounded_path.res != path.res {
|
||||
return None;
|
||||
}
|
||||
predicate.bounds.iter().find_map(|bound| {
|
||||
let hir::GenericBound::Trait(trait_, _) = bound else {
|
||||
return None;
|
||||
};
|
||||
BoundVarContext::supertrait_hrtb_vars(
|
||||
self.tcx,
|
||||
trait_.trait_ref.trait_def_id()?,
|
||||
item_segment.ident,
|
||||
ty::AssocKind::Fn,
|
||||
)
|
||||
})
|
||||
});
|
||||
let Some((bound_vars, assoc_item)) = one_bound else {
|
||||
return;
|
||||
};
|
||||
(bound_vars, assoc_item.def_id, item_segment)
|
||||
}
|
||||
// If we have a self type alias (in an impl), try to resolve an
|
||||
// associated item from one of the supertraits of the impl's trait.
|
||||
Res::SelfTyAlias { alias_to: impl_def_id, is_trait_impl: true, .. } => {
|
||||
let hir::ItemKind::Impl(hir::Impl { of_trait: Some(trait_ref), .. }) = self
|
||||
.tcx
|
||||
.hir_node_by_def_id(impl_def_id.expect_local())
|
||||
.expect_item()
|
||||
.kind
|
||||
else {
|
||||
return;
|
||||
};
|
||||
let Some(trait_def_id) = trait_ref.trait_def_id() else {
|
||||
return;
|
||||
};
|
||||
let Some((bound_vars, assoc_item)) = BoundVarContext::supertrait_hrtb_vars(
|
||||
self.tcx,
|
||||
trait_def_id,
|
||||
item_segment.ident,
|
||||
ty::AssocKind::Fn,
|
||||
) else {
|
||||
return;
|
||||
};
|
||||
(bound_vars, assoc_item.def_id, item_segment)
|
||||
}
|
||||
_ => return,
|
||||
}
|
||||
}
|
||||
|
||||
_ => return,
|
||||
};
|
||||
|
||||
// Append the early-bound vars on the function, and then the late-bound ones.
|
||||
// We actually turn type parameters into higher-ranked types here, but we
|
||||
// deny them later in HIR lowering.
|
||||
bound_vars.extend(self.tcx.generics_of(item_def_id).own_params.iter().map(|param| {
|
||||
match param.kind {
|
||||
ty::GenericParamDefKind::Lifetime => ty::BoundVariableKind::Region(
|
||||
ty::BoundRegionKind::BrNamed(param.def_id, param.name),
|
||||
),
|
||||
ty::GenericParamDefKind::Type { .. } => {
|
||||
ty::BoundVariableKind::Ty(ty::BoundTyKind::Param(param.def_id, param.name))
|
||||
}
|
||||
ty::GenericParamDefKind::Const { .. } => ty::BoundVariableKind::Const,
|
||||
}
|
||||
}));
|
||||
bound_vars.extend(self.tcx.fn_sig(item_def_id).instantiate_identity().bound_vars());
|
||||
|
||||
// SUBTLE: Stash the old bound vars onto the *item segment* before appending
|
||||
// the new bound vars. We do this because we need to know how many bound vars
|
||||
// are present on the binder explicitly (i.e. not return-type-notation vars)
|
||||
// to do bound var shifting correctly in HIR lowering.
|
||||
//
|
||||
// For example, in `where for<'a> <T as Trait<'a>>::method(..): Other`,
|
||||
// the `late_bound_vars` of the where clause predicate (i.e. this HIR ty's
|
||||
// parent) will include `'a` AND all the early- and late-bound vars of the
|
||||
// method. But when lowering the RTN type, we just want the list of vars
|
||||
// we used to resolve the trait ref. We explicitly stored those back onto
|
||||
// the item segment, since there's no other good place to put them.
|
||||
//
|
||||
// See where these vars are used in `HirTyLowerer::lower_ty_maybe_return_type_notation`.
|
||||
// And this is exercised in:
|
||||
// `tests/ui/associated-type-bounds/return-type-notation/higher-ranked-bound-works.rs`.
|
||||
let existing_bound_vars = self.map.late_bound_vars.get_mut(&hir_id).unwrap();
|
||||
let existing_bound_vars_saved = existing_bound_vars.clone();
|
||||
existing_bound_vars.extend(bound_vars);
|
||||
self.record_late_bound_vars(item_segment.hir_id, existing_bound_vars_saved);
|
||||
}
|
||||
}
|
||||
|
||||
/// Detects late-bound lifetimes and inserts them into
|
||||
|
|
|
@ -780,14 +780,15 @@ pub(crate) struct PlaceholderNotAllowedItemSignatures {
|
|||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(hir_analysis_associated_type_trait_uninferred_generic_params, code = E0212)]
|
||||
pub(crate) struct AssociatedTypeTraitUninferredGenericParams {
|
||||
pub(crate) struct AssociatedItemTraitUninferredGenericParams {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
#[suggestion(style = "verbose", applicability = "maybe-incorrect", code = "{bound}")]
|
||||
pub inferred_sugg: Option<Span>,
|
||||
pub bound: String,
|
||||
#[subdiagnostic]
|
||||
pub mpart_sugg: Option<AssociatedTypeTraitUninferredGenericParamsMultipartSuggestion>,
|
||||
pub mpart_sugg: Option<AssociatedItemTraitUninferredGenericParamsMultipartSuggestion>,
|
||||
pub what: &'static str,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
|
@ -795,7 +796,7 @@ pub(crate) struct AssociatedTypeTraitUninferredGenericParams {
|
|||
hir_analysis_associated_type_trait_uninferred_generic_params_multipart_suggestion,
|
||||
applicability = "maybe-incorrect"
|
||||
)]
|
||||
pub(crate) struct AssociatedTypeTraitUninferredGenericParamsMultipartSuggestion {
|
||||
pub(crate) struct AssociatedItemTraitUninferredGenericParamsMultipartSuggestion {
|
||||
#[suggestion_part(code = "{first}")]
|
||||
pub fspan: Span,
|
||||
pub first: String,
|
||||
|
@ -1693,3 +1694,10 @@ pub(crate) struct CmseCallGeneric {
|
|||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(hir_analysis_bad_return_type_notation_position)]
|
||||
pub(crate) struct BadReturnTypeNotation {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@ use rustc_errors::struct_span_code_err;
|
|||
use rustc_hir as hir;
|
||||
use rustc_hir::def::{DefKind, Res};
|
||||
use rustc_hir::def_id::{DefId, LocalDefId};
|
||||
use rustc_hir::HirId;
|
||||
use rustc_middle::bug;
|
||||
use rustc_middle::ty::{self as ty, IsSuggestable, Ty, TyCtxt};
|
||||
use rustc_span::symbol::Ident;
|
||||
|
@ -15,6 +16,7 @@ use rustc_type_ir::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitableExt,
|
|||
use smallvec::SmallVec;
|
||||
use tracing::{debug, instrument};
|
||||
|
||||
use super::errors::GenericsArgsErrExtend;
|
||||
use crate::bounds::Bounds;
|
||||
use crate::errors;
|
||||
use crate::hir_ty_lowering::{
|
||||
|
@ -332,74 +334,11 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
.or_insert(constraint.span);
|
||||
|
||||
let projection_term = if let ty::AssocKind::Fn = assoc_kind {
|
||||
let mut emitted_bad_param_err = None;
|
||||
// If we have an method return type bound, then we need to instantiate
|
||||
// the method's early bound params with suitable late-bound params.
|
||||
let mut num_bound_vars = candidate.bound_vars().len();
|
||||
let args =
|
||||
candidate.skip_binder().args.extend_to(tcx, assoc_item.def_id, |param, _| {
|
||||
let arg = match param.kind {
|
||||
ty::GenericParamDefKind::Lifetime => ty::Region::new_bound(
|
||||
tcx,
|
||||
ty::INNERMOST,
|
||||
ty::BoundRegion {
|
||||
var: ty::BoundVar::from_usize(num_bound_vars),
|
||||
kind: ty::BoundRegionKind::BrNamed(param.def_id, param.name),
|
||||
},
|
||||
)
|
||||
.into(),
|
||||
ty::GenericParamDefKind::Type { .. } => {
|
||||
let guar = *emitted_bad_param_err.get_or_insert_with(|| {
|
||||
self.dcx().emit_err(
|
||||
crate::errors::ReturnTypeNotationIllegalParam::Type {
|
||||
span: path_span,
|
||||
param_span: tcx.def_span(param.def_id),
|
||||
},
|
||||
)
|
||||
});
|
||||
Ty::new_error(tcx, guar).into()
|
||||
}
|
||||
ty::GenericParamDefKind::Const { .. } => {
|
||||
let guar = *emitted_bad_param_err.get_or_insert_with(|| {
|
||||
self.dcx().emit_err(
|
||||
crate::errors::ReturnTypeNotationIllegalParam::Const {
|
||||
span: path_span,
|
||||
param_span: tcx.def_span(param.def_id),
|
||||
},
|
||||
)
|
||||
});
|
||||
ty::Const::new_error(tcx, guar).into()
|
||||
}
|
||||
};
|
||||
num_bound_vars += 1;
|
||||
arg
|
||||
});
|
||||
|
||||
// Next, we need to check that the return-type notation is being used on
|
||||
// an RPITIT (return-position impl trait in trait) or AFIT (async fn in trait).
|
||||
let output = tcx.fn_sig(assoc_item.def_id).skip_binder().output();
|
||||
let output = if let ty::Alias(ty::Projection, alias_ty) = *output.skip_binder().kind()
|
||||
&& tcx.is_impl_trait_in_trait(alias_ty.def_id)
|
||||
{
|
||||
alias_ty.into()
|
||||
} else {
|
||||
return Err(self.dcx().emit_err(crate::errors::ReturnTypeNotationOnNonRpitit {
|
||||
span: constraint.span,
|
||||
ty: tcx.liberate_late_bound_regions(assoc_item.def_id, output),
|
||||
fn_span: tcx.hir().span_if_local(assoc_item.def_id),
|
||||
note: (),
|
||||
}));
|
||||
};
|
||||
|
||||
// Finally, move the fn return type's bound vars over to account for the early bound
|
||||
// params (and trait ref's late bound params). This logic is very similar to
|
||||
// `rustc_middle::ty::predicate::Clause::instantiate_supertrait`
|
||||
// and it's no coincidence why.
|
||||
let shifted_output = tcx.shift_bound_var_indices(num_bound_vars, output);
|
||||
let instantiation_output = ty::EarlyBinder::bind(shifted_output).instantiate(tcx, args);
|
||||
|
||||
let bound_vars = tcx.late_bound_vars(constraint.hir_id);
|
||||
ty::Binder::bind_with_vars(instantiation_output, bound_vars)
|
||||
ty::Binder::bind_with_vars(
|
||||
self.lower_return_type_notation_ty(candidate, assoc_item.def_id, path_span)?.into(),
|
||||
bound_vars,
|
||||
)
|
||||
} else {
|
||||
// Create the generic arguments for the associated type or constant by joining the
|
||||
// parent arguments (the arguments of the trait) and the own arguments (the ones of
|
||||
|
@ -525,6 +464,269 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Lower a type, possibly specially handling the type if it's a return type notation
|
||||
/// which we otherwise deny in other positions.
|
||||
pub fn lower_ty_maybe_return_type_notation(&self, hir_ty: &hir::Ty<'tcx>) -> Ty<'tcx> {
|
||||
let hir::TyKind::Path(qpath) = hir_ty.kind else {
|
||||
return self.lower_ty(hir_ty);
|
||||
};
|
||||
|
||||
let tcx = self.tcx();
|
||||
match qpath {
|
||||
hir::QPath::Resolved(opt_self_ty, path)
|
||||
if let [mod_segments @ .., trait_segment, item_segment] = &path.segments[..]
|
||||
&& item_segment.args.is_some_and(|args| {
|
||||
matches!(
|
||||
args.parenthesized,
|
||||
hir::GenericArgsParentheses::ReturnTypeNotation
|
||||
)
|
||||
}) =>
|
||||
{
|
||||
// We don't allow generics on the module segments.
|
||||
let _ =
|
||||
self.prohibit_generic_args(mod_segments.iter(), GenericsArgsErrExtend::None);
|
||||
|
||||
let item_def_id = match path.res {
|
||||
Res::Def(DefKind::AssocFn, item_def_id) => item_def_id,
|
||||
Res::Err => {
|
||||
return Ty::new_error_with_message(
|
||||
tcx,
|
||||
hir_ty.span,
|
||||
"failed to resolve RTN",
|
||||
);
|
||||
}
|
||||
_ => bug!("only expected method resolution for fully qualified RTN"),
|
||||
};
|
||||
let trait_def_id = tcx.parent(item_def_id);
|
||||
|
||||
// Good error for `where Trait::method(..): Send`.
|
||||
let Some(self_ty) = opt_self_ty else {
|
||||
return self.error_missing_qpath_self_ty(
|
||||
trait_def_id,
|
||||
hir_ty.span,
|
||||
item_segment,
|
||||
);
|
||||
};
|
||||
let self_ty = self.lower_ty(self_ty);
|
||||
|
||||
let trait_ref = self.lower_mono_trait_ref(
|
||||
hir_ty.span,
|
||||
trait_def_id,
|
||||
self_ty,
|
||||
trait_segment,
|
||||
false,
|
||||
ty::BoundConstness::NotConst,
|
||||
);
|
||||
|
||||
// SUBTLE: As noted at the end of `try_append_return_type_notation_params`
|
||||
// in `resolve_bound_vars`, we stash the explicit bound vars of the where
|
||||
// clause onto the item segment of the RTN type. This allows us to know
|
||||
// how many bound vars are *not* coming from the signature of the function
|
||||
// from lowering RTN itself.
|
||||
//
|
||||
// For example, in `where for<'a> <T as Trait<'a>>::method(..): Other`,
|
||||
// the `late_bound_vars` of the where clause predicate (i.e. this HIR ty's
|
||||
// parent) will include `'a` AND all the early- and late-bound vars of the
|
||||
// method. But when lowering the RTN type, we just want the list of vars
|
||||
// we used to resolve the trait ref. We explicitly stored those back onto
|
||||
// the item segment, since there's no other good place to put them.
|
||||
let candidate =
|
||||
ty::Binder::bind_with_vars(trait_ref, tcx.late_bound_vars(item_segment.hir_id));
|
||||
|
||||
match self.lower_return_type_notation_ty(candidate, item_def_id, hir_ty.span) {
|
||||
Ok(ty) => Ty::new_alias(tcx, ty::Projection, ty),
|
||||
Err(guar) => Ty::new_error(tcx, guar),
|
||||
}
|
||||
}
|
||||
hir::QPath::TypeRelative(qself, item_segment)
|
||||
if item_segment.args.is_some_and(|args| {
|
||||
matches!(args.parenthesized, hir::GenericArgsParentheses::ReturnTypeNotation)
|
||||
}) =>
|
||||
{
|
||||
match self
|
||||
.resolve_type_relative_return_type_notation(
|
||||
qself,
|
||||
item_segment,
|
||||
hir_ty.hir_id,
|
||||
hir_ty.span,
|
||||
)
|
||||
.and_then(|(candidate, item_def_id)| {
|
||||
self.lower_return_type_notation_ty(candidate, item_def_id, hir_ty.span)
|
||||
}) {
|
||||
Ok(ty) => Ty::new_alias(tcx, ty::Projection, ty),
|
||||
Err(guar) => Ty::new_error(tcx, guar),
|
||||
}
|
||||
}
|
||||
_ => self.lower_ty(hir_ty),
|
||||
}
|
||||
}
|
||||
|
||||
/// Perform type-dependent lookup for a *method* for return type notation.
|
||||
/// This generally mirrors `<dyn HirTyLowerer>::lower_assoc_path`.
|
||||
fn resolve_type_relative_return_type_notation(
|
||||
&self,
|
||||
qself: &'tcx hir::Ty<'tcx>,
|
||||
item_segment: &'tcx hir::PathSegment<'tcx>,
|
||||
qpath_hir_id: HirId,
|
||||
span: Span,
|
||||
) -> Result<(ty::PolyTraitRef<'tcx>, DefId), ErrorGuaranteed> {
|
||||
let tcx = self.tcx();
|
||||
let qself_ty = self.lower_ty(qself);
|
||||
let assoc_ident = item_segment.ident;
|
||||
let qself_res = if let hir::TyKind::Path(hir::QPath::Resolved(_, path)) = &qself.kind {
|
||||
path.res
|
||||
} else {
|
||||
Res::Err
|
||||
};
|
||||
|
||||
let bound = match (qself_ty.kind(), qself_res) {
|
||||
(_, Res::SelfTyAlias { alias_to: impl_def_id, is_trait_impl: true, .. }) => {
|
||||
// `Self` in an impl of a trait -- we have a concrete self type and a
|
||||
// trait reference.
|
||||
let Some(trait_ref) = tcx.impl_trait_ref(impl_def_id) else {
|
||||
// A cycle error occurred, most likely.
|
||||
self.dcx().span_bug(span, "expected cycle error");
|
||||
};
|
||||
|
||||
self.probe_single_bound_for_assoc_item(
|
||||
|| {
|
||||
traits::supertraits(
|
||||
tcx,
|
||||
ty::Binder::dummy(trait_ref.instantiate_identity()),
|
||||
)
|
||||
},
|
||||
AssocItemQSelf::SelfTyAlias,
|
||||
ty::AssocKind::Fn,
|
||||
assoc_ident,
|
||||
span,
|
||||
None,
|
||||
)?
|
||||
}
|
||||
(
|
||||
&ty::Param(_),
|
||||
Res::SelfTyParam { trait_: param_did } | Res::Def(DefKind::TyParam, param_did),
|
||||
) => self.probe_single_ty_param_bound_for_assoc_item(
|
||||
param_did.expect_local(),
|
||||
qself.span,
|
||||
ty::AssocKind::Fn,
|
||||
assoc_ident,
|
||||
span,
|
||||
)?,
|
||||
_ => {
|
||||
if let Err(reported) = qself_ty.error_reported() {
|
||||
return Err(reported);
|
||||
} else {
|
||||
// FIXME(return_type_notation): Provide some structured suggestion here.
|
||||
let err = struct_span_code_err!(
|
||||
self.dcx(),
|
||||
span,
|
||||
E0223,
|
||||
"ambiguous associated function"
|
||||
);
|
||||
return Err(err.emit());
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Don't let `T::method` resolve to some `for<'a> <T as Tr<'a>>::method`,
|
||||
// which may happen via a higher-ranked where clause or supertrait.
|
||||
// This is the same restrictions as associated types; even though we could
|
||||
// support it, it just makes things a lot more difficult to support in
|
||||
// `resolve_bound_vars`, since we'd need to introduce those as elided
|
||||
// bound vars on the where clause too.
|
||||
if bound.has_bound_vars() {
|
||||
return Err(self.tcx().dcx().emit_err(
|
||||
errors::AssociatedItemTraitUninferredGenericParams {
|
||||
span,
|
||||
inferred_sugg: Some(span.with_hi(item_segment.ident.span.lo())),
|
||||
bound: format!("{}::", tcx.anonymize_bound_vars(bound).skip_binder(),),
|
||||
mpart_sugg: None,
|
||||
what: "function",
|
||||
},
|
||||
));
|
||||
}
|
||||
|
||||
let trait_def_id = bound.def_id();
|
||||
let assoc_ty = self
|
||||
.probe_assoc_item(assoc_ident, ty::AssocKind::Fn, qpath_hir_id, span, trait_def_id)
|
||||
.expect("failed to find associated type");
|
||||
|
||||
Ok((bound, assoc_ty.def_id))
|
||||
}
|
||||
|
||||
/// Do the common parts of lowering an RTN type. This involves extending the
|
||||
/// candidate binder to include all of the early- and late-bound vars that are
|
||||
/// defined on the function itself, and constructing a projection to the RPITIT
|
||||
/// return type of that function.
|
||||
fn lower_return_type_notation_ty(
|
||||
&self,
|
||||
candidate: ty::PolyTraitRef<'tcx>,
|
||||
item_def_id: DefId,
|
||||
path_span: Span,
|
||||
) -> Result<ty::AliasTy<'tcx>, ErrorGuaranteed> {
|
||||
let tcx = self.tcx();
|
||||
let mut emitted_bad_param_err = None;
|
||||
// If we have an method return type bound, then we need to instantiate
|
||||
// the method's early bound params with suitable late-bound params.
|
||||
let mut num_bound_vars = candidate.bound_vars().len();
|
||||
let args = candidate.skip_binder().args.extend_to(tcx, item_def_id, |param, _| {
|
||||
let arg = match param.kind {
|
||||
ty::GenericParamDefKind::Lifetime => ty::Region::new_bound(
|
||||
tcx,
|
||||
ty::INNERMOST,
|
||||
ty::BoundRegion {
|
||||
var: ty::BoundVar::from_usize(num_bound_vars),
|
||||
kind: ty::BoundRegionKind::BrNamed(param.def_id, param.name),
|
||||
},
|
||||
)
|
||||
.into(),
|
||||
ty::GenericParamDefKind::Type { .. } => {
|
||||
let guar = *emitted_bad_param_err.get_or_insert_with(|| {
|
||||
self.dcx().emit_err(crate::errors::ReturnTypeNotationIllegalParam::Type {
|
||||
span: path_span,
|
||||
param_span: tcx.def_span(param.def_id),
|
||||
})
|
||||
});
|
||||
Ty::new_error(tcx, guar).into()
|
||||
}
|
||||
ty::GenericParamDefKind::Const { .. } => {
|
||||
let guar = *emitted_bad_param_err.get_or_insert_with(|| {
|
||||
self.dcx().emit_err(crate::errors::ReturnTypeNotationIllegalParam::Const {
|
||||
span: path_span,
|
||||
param_span: tcx.def_span(param.def_id),
|
||||
})
|
||||
});
|
||||
ty::Const::new_error(tcx, guar).into()
|
||||
}
|
||||
};
|
||||
num_bound_vars += 1;
|
||||
arg
|
||||
});
|
||||
|
||||
// Next, we need to check that the return-type notation is being used on
|
||||
// an RPITIT (return-position impl trait in trait) or AFIT (async fn in trait).
|
||||
let output = tcx.fn_sig(item_def_id).skip_binder().output();
|
||||
let output = if let ty::Alias(ty::Projection, alias_ty) = *output.skip_binder().kind()
|
||||
&& tcx.is_impl_trait_in_trait(alias_ty.def_id)
|
||||
{
|
||||
alias_ty
|
||||
} else {
|
||||
return Err(self.dcx().emit_err(crate::errors::ReturnTypeNotationOnNonRpitit {
|
||||
span: path_span,
|
||||
ty: tcx.liberate_late_bound_regions(item_def_id, output),
|
||||
fn_span: tcx.hir().span_if_local(item_def_id),
|
||||
note: (),
|
||||
}));
|
||||
};
|
||||
|
||||
// Finally, move the fn return type's bound vars over to account for the early bound
|
||||
// params (and trait ref's late bound params). This logic is very similar to
|
||||
// `rustc_middle::ty::predicate::Clause::instantiate_supertrait`
|
||||
// and it's no coincidence why.
|
||||
let shifted_output = tcx.shift_bound_var_indices(num_bound_vars, output);
|
||||
Ok(ty::EarlyBinder::bind(shifted_output).instantiate(tcx, args))
|
||||
}
|
||||
}
|
||||
|
||||
/// Detect and reject early-bound & escaping late-bound generic params in the type of assoc const bindings.
|
||||
|
|
|
@ -53,7 +53,7 @@ use rustc_trait_selection::traits::{self, ObligationCtxt};
|
|||
use tracing::{debug, debug_span, instrument};
|
||||
|
||||
use crate::bounds::Bounds;
|
||||
use crate::errors::{AmbiguousLifetimeBound, WildPatTy};
|
||||
use crate::errors::{AmbiguousLifetimeBound, BadReturnTypeNotation, WildPatTy};
|
||||
use crate::hir_ty_lowering::errors::{prohibit_assoc_item_constraint, GenericsArgsErrExtend};
|
||||
use crate::hir_ty_lowering::generics::{check_generic_arg_count, lower_generic_args};
|
||||
use crate::middle::resolve_bound_vars as rbv;
|
||||
|
@ -813,17 +813,19 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
}
|
||||
}
|
||||
|
||||
/// Search for a trait bound on a type parameter whose trait defines the associated type given by `assoc_name`.
|
||||
/// Search for a trait bound on a type parameter whose trait defines the associated item
|
||||
/// given by `assoc_name` and `kind`.
|
||||
///
|
||||
/// This fails if there is no such bound in the list of candidates or if there are multiple
|
||||
/// candidates in which case it reports ambiguity.
|
||||
///
|
||||
/// `ty_param_def_id` is the `LocalDefId` of the type parameter.
|
||||
#[instrument(level = "debug", skip_all, ret)]
|
||||
fn probe_single_ty_param_bound_for_assoc_ty(
|
||||
fn probe_single_ty_param_bound_for_assoc_item(
|
||||
&self,
|
||||
ty_param_def_id: LocalDefId,
|
||||
ty_param_span: Span,
|
||||
kind: ty::AssocKind,
|
||||
assoc_name: Ident,
|
||||
span: Span,
|
||||
) -> Result<ty::PolyTraitRef<'tcx>, ErrorGuaranteed> {
|
||||
|
@ -841,7 +843,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
traits::transitive_bounds_that_define_assoc_item(tcx, trait_refs, assoc_name)
|
||||
},
|
||||
AssocItemQSelf::TyParam(ty_param_def_id, ty_param_span),
|
||||
ty::AssocKind::Type,
|
||||
kind,
|
||||
assoc_name,
|
||||
span,
|
||||
None,
|
||||
|
@ -1081,9 +1083,10 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
(
|
||||
&ty::Param(_),
|
||||
Res::SelfTyParam { trait_: param_did } | Res::Def(DefKind::TyParam, param_did),
|
||||
) => self.probe_single_ty_param_bound_for_assoc_ty(
|
||||
) => self.probe_single_ty_param_bound_for_assoc_item(
|
||||
param_did.expect_local(),
|
||||
qself.span,
|
||||
ty::AssocKind::Type,
|
||||
assoc_ident,
|
||||
span,
|
||||
)?,
|
||||
|
@ -1545,48 +1548,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
debug!(?trait_def_id);
|
||||
|
||||
let Some(self_ty) = opt_self_ty else {
|
||||
let path_str = tcx.def_path_str(trait_def_id);
|
||||
|
||||
let def_id = self.item_def_id();
|
||||
debug!(item_def_id = ?def_id);
|
||||
|
||||
// FIXME: document why/how this is different from `tcx.local_parent(def_id)`
|
||||
let parent_def_id =
|
||||
tcx.hir().get_parent_item(tcx.local_def_id_to_hir_id(def_id)).to_def_id();
|
||||
debug!(?parent_def_id);
|
||||
|
||||
// If the trait in segment is the same as the trait defining the item,
|
||||
// use the `<Self as ..>` syntax in the error.
|
||||
let is_part_of_self_trait_constraints = def_id.to_def_id() == trait_def_id;
|
||||
let is_part_of_fn_in_self_trait = parent_def_id == trait_def_id;
|
||||
|
||||
let type_names = if is_part_of_self_trait_constraints || is_part_of_fn_in_self_trait {
|
||||
vec!["Self".to_string()]
|
||||
} else {
|
||||
// Find all the types that have an `impl` for the trait.
|
||||
tcx.all_impls(trait_def_id)
|
||||
.filter_map(|impl_def_id| tcx.impl_trait_header(impl_def_id))
|
||||
.filter(|header| {
|
||||
// Consider only accessible traits
|
||||
tcx.visibility(trait_def_id).is_accessible_from(self.item_def_id(), tcx)
|
||||
&& header.polarity != ty::ImplPolarity::Negative
|
||||
})
|
||||
.map(|header| header.trait_ref.instantiate_identity().self_ty())
|
||||
// We don't care about blanket impls.
|
||||
.filter(|self_ty| !self_ty.has_non_region_param())
|
||||
.map(|self_ty| tcx.erase_regions(self_ty).to_string())
|
||||
.collect()
|
||||
};
|
||||
// FIXME: also look at `tcx.generics_of(self.item_def_id()).params` any that
|
||||
// references the trait. Relevant for the first case in
|
||||
// `src/test/ui/associated-types/associated-types-in-ambiguous-context.rs`
|
||||
let reported = self.report_ambiguous_assoc_ty(
|
||||
span,
|
||||
&type_names,
|
||||
&[path_str],
|
||||
item_segment.ident.name,
|
||||
);
|
||||
return Ty::new_error(tcx, reported);
|
||||
return self.error_missing_qpath_self_ty(trait_def_id, span, item_segment);
|
||||
};
|
||||
debug!(?self_ty);
|
||||
|
||||
|
@ -1600,6 +1562,53 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
Ty::new_projection_from_args(tcx, item_def_id, item_args)
|
||||
}
|
||||
|
||||
fn error_missing_qpath_self_ty(
|
||||
&self,
|
||||
trait_def_id: DefId,
|
||||
span: Span,
|
||||
item_segment: &hir::PathSegment<'tcx>,
|
||||
) -> Ty<'tcx> {
|
||||
let tcx = self.tcx();
|
||||
let path_str = tcx.def_path_str(trait_def_id);
|
||||
|
||||
let def_id = self.item_def_id();
|
||||
debug!(item_def_id = ?def_id);
|
||||
|
||||
// FIXME: document why/how this is different from `tcx.local_parent(def_id)`
|
||||
let parent_def_id =
|
||||
tcx.hir().get_parent_item(tcx.local_def_id_to_hir_id(def_id)).to_def_id();
|
||||
debug!(?parent_def_id);
|
||||
|
||||
// If the trait in segment is the same as the trait defining the item,
|
||||
// use the `<Self as ..>` syntax in the error.
|
||||
let is_part_of_self_trait_constraints = def_id.to_def_id() == trait_def_id;
|
||||
let is_part_of_fn_in_self_trait = parent_def_id == trait_def_id;
|
||||
|
||||
let type_names = if is_part_of_self_trait_constraints || is_part_of_fn_in_self_trait {
|
||||
vec!["Self".to_string()]
|
||||
} else {
|
||||
// Find all the types that have an `impl` for the trait.
|
||||
tcx.all_impls(trait_def_id)
|
||||
.filter_map(|impl_def_id| tcx.impl_trait_header(impl_def_id))
|
||||
.filter(|header| {
|
||||
// Consider only accessible traits
|
||||
tcx.visibility(trait_def_id).is_accessible_from(self.item_def_id(), tcx)
|
||||
&& header.polarity != ty::ImplPolarity::Negative
|
||||
})
|
||||
.map(|header| header.trait_ref.instantiate_identity().self_ty())
|
||||
// We don't care about blanket impls.
|
||||
.filter(|self_ty| !self_ty.has_non_region_param())
|
||||
.map(|self_ty| tcx.erase_regions(self_ty).to_string())
|
||||
.collect()
|
||||
};
|
||||
// FIXME: also look at `tcx.generics_of(self.item_def_id()).params` any that
|
||||
// references the trait. Relevant for the first case in
|
||||
// `src/test/ui/associated-types/associated-types-in-ambiguous-context.rs`
|
||||
let reported =
|
||||
self.report_ambiguous_assoc_ty(span, &type_names, &[path_str], item_segment.ident.name);
|
||||
Ty::new_error(tcx, reported)
|
||||
}
|
||||
|
||||
pub fn prohibit_generic_args<'a>(
|
||||
&self,
|
||||
segments: impl Iterator<Item = &'a hir::PathSegment<'a>> + Clone,
|
||||
|
@ -1930,7 +1939,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
.tcx()
|
||||
.dcx()
|
||||
.span_delayed_bug(path.span, "path with `Res::Err` but no error emitted");
|
||||
Ty::new_error(self.tcx(), e)
|
||||
Ty::new_error(tcx, e)
|
||||
}
|
||||
Res::Def(..) => {
|
||||
assert_eq!(
|
||||
|
@ -2061,6 +2070,17 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
};
|
||||
self.lower_trait_object_ty(hir_ty.span, hir_ty.hir_id, bounds, lifetime, repr)
|
||||
}
|
||||
// If we encounter a fully qualified path with RTN generics, then it must have
|
||||
// *not* gone through `lower_ty_maybe_return_type_notation`, and therefore
|
||||
// it's certainly in an illegal position.
|
||||
hir::TyKind::Path(hir::QPath::Resolved(_, path))
|
||||
if path.segments.last().and_then(|segment| segment.args).is_some_and(|args| {
|
||||
matches!(args.parenthesized, hir::GenericArgsParentheses::ReturnTypeNotation)
|
||||
}) =>
|
||||
{
|
||||
let guar = self.dcx().emit_err(BadReturnTypeNotation { span: hir_ty.span });
|
||||
Ty::new_error(tcx, guar)
|
||||
}
|
||||
hir::TyKind::Path(hir::QPath::Resolved(maybe_qself, path)) => {
|
||||
debug!(?maybe_qself, ?path);
|
||||
let opt_self_ty = maybe_qself.as_ref().map(|qself| self.lower_ty(qself));
|
||||
|
@ -2085,6 +2105,17 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
ref i => bug!("`impl Trait` pointed to non-opaque type?? {:#?}", i),
|
||||
}
|
||||
}
|
||||
// If we encounter a type relative path with RTN generics, then it must have
|
||||
// *not* gone through `lower_ty_maybe_return_type_notation`, and therefore
|
||||
// it's certainly in an illegal position.
|
||||
hir::TyKind::Path(hir::QPath::TypeRelative(_, segment))
|
||||
if segment.args.is_some_and(|args| {
|
||||
matches!(args.parenthesized, hir::GenericArgsParentheses::ReturnTypeNotation)
|
||||
}) =>
|
||||
{
|
||||
let guar = self.dcx().emit_err(BadReturnTypeNotation { span: hir_ty.span });
|
||||
Ty::new_error(tcx, guar)
|
||||
}
|
||||
hir::TyKind::Path(hir::QPath::TypeRelative(qself, segment)) => {
|
||||
debug!(?qself, ?segment);
|
||||
let ty = self.lower_ty(qself);
|
||||
|
|
|
@ -404,6 +404,8 @@ pub(crate) enum PathSource<'a> {
|
|||
Delegation,
|
||||
/// An arg in a `use<'a, N>` precise-capturing bound.
|
||||
PreciseCapturingArg(Namespace),
|
||||
// Paths that end with `(..)`, for return type notation.
|
||||
ReturnTypeNotation,
|
||||
}
|
||||
|
||||
impl<'a> PathSource<'a> {
|
||||
|
@ -413,7 +415,8 @@ impl<'a> PathSource<'a> {
|
|||
PathSource::Expr(..)
|
||||
| PathSource::Pat
|
||||
| PathSource::TupleStruct(..)
|
||||
| PathSource::Delegation => ValueNS,
|
||||
| PathSource::Delegation
|
||||
| PathSource::ReturnTypeNotation => ValueNS,
|
||||
PathSource::TraitItem(ns) => ns,
|
||||
PathSource::PreciseCapturingArg(ns) => ns,
|
||||
}
|
||||
|
@ -425,7 +428,8 @@ impl<'a> PathSource<'a> {
|
|||
| PathSource::Expr(..)
|
||||
| PathSource::Pat
|
||||
| PathSource::Struct
|
||||
| PathSource::TupleStruct(..) => true,
|
||||
| PathSource::TupleStruct(..)
|
||||
| PathSource::ReturnTypeNotation => true,
|
||||
PathSource::Trait(_)
|
||||
| PathSource::TraitItem(..)
|
||||
| PathSource::Delegation
|
||||
|
@ -471,7 +475,7 @@ impl<'a> PathSource<'a> {
|
|||
},
|
||||
_ => "value",
|
||||
},
|
||||
PathSource::Delegation => "function",
|
||||
PathSource::ReturnTypeNotation | PathSource::Delegation => "function",
|
||||
PathSource::PreciseCapturingArg(..) => "type or const parameter",
|
||||
}
|
||||
}
|
||||
|
@ -540,6 +544,10 @@ impl<'a> PathSource<'a> {
|
|||
Res::Def(DefKind::AssocTy, _) if ns == TypeNS => true,
|
||||
_ => false,
|
||||
},
|
||||
PathSource::ReturnTypeNotation => match res {
|
||||
Res::Def(DefKind::AssocFn, _) => true,
|
||||
_ => false,
|
||||
},
|
||||
PathSource::Delegation => matches!(res, Res::Def(DefKind::Fn | DefKind::AssocFn, _)),
|
||||
PathSource::PreciseCapturingArg(ValueNS) => {
|
||||
matches!(res, Res::Def(DefKind::ConstParam, _))
|
||||
|
@ -565,8 +573,8 @@ impl<'a> PathSource<'a> {
|
|||
(PathSource::Expr(..), false) | (PathSource::Delegation, false) => E0425,
|
||||
(PathSource::Pat | PathSource::TupleStruct(..), true) => E0532,
|
||||
(PathSource::Pat | PathSource::TupleStruct(..), false) => E0531,
|
||||
(PathSource::TraitItem(..), true) => E0575,
|
||||
(PathSource::TraitItem(..), false) => E0576,
|
||||
(PathSource::TraitItem(..), true) | (PathSource::ReturnTypeNotation, true) => E0575,
|
||||
(PathSource::TraitItem(..), false) | (PathSource::ReturnTypeNotation, false) => E0576,
|
||||
(PathSource::PreciseCapturingArg(..), true) => E0799,
|
||||
(PathSource::PreciseCapturingArg(..), false) => E0800,
|
||||
}
|
||||
|
@ -781,7 +789,20 @@ impl<'ra: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'_, 'ast, 'r
|
|||
}
|
||||
TyKind::Path(qself, path) => {
|
||||
self.diag_metadata.current_type_path = Some(ty);
|
||||
self.smart_resolve_path(ty.id, qself, path, PathSource::Type);
|
||||
|
||||
// If we have a path that ends with `(..)`, then it must be
|
||||
// return type notation. Resolve that path in the *value*
|
||||
// namespace.
|
||||
let source = if let Some(seg) = path.segments.last()
|
||||
&& let Some(args) = &seg.args
|
||||
&& matches!(**args, GenericArgs::ParenthesizedElided(..))
|
||||
{
|
||||
PathSource::ReturnTypeNotation
|
||||
} else {
|
||||
PathSource::Type
|
||||
};
|
||||
|
||||
self.smart_resolve_path(ty.id, qself, path, source);
|
||||
|
||||
// Check whether we should interpret this as a bare trait object.
|
||||
if qself.is_none()
|
||||
|
@ -1920,7 +1941,8 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
|
|||
PathSource::Trait(..)
|
||||
| PathSource::TraitItem(..)
|
||||
| PathSource::Type
|
||||
| PathSource::PreciseCapturingArg(..) => false,
|
||||
| PathSource::PreciseCapturingArg(..)
|
||||
| PathSource::ReturnTypeNotation => false,
|
||||
PathSource::Expr(..)
|
||||
| PathSource::Pat
|
||||
| PathSource::Struct
|
||||
|
|
|
@ -16,4 +16,22 @@ fn bar<T: Trait<method() -> (): Send>>() {}
|
|||
fn baz<T: Trait<method(): Send>>() {}
|
||||
//~^ ERROR return type notation arguments must be elided with `..`
|
||||
|
||||
fn foo_path<T: Trait>() where T::method(i32): Send {}
|
||||
//~^ ERROR argument types not allowed with return type notation
|
||||
|
||||
fn bar_path<T: Trait>() where T::method() -> (): Send {}
|
||||
//~^ ERROR return type not allowed with return type notation
|
||||
|
||||
fn baz_path<T: Trait>() where T::method(): Send {}
|
||||
//~^ ERROR return type notation arguments must be elided with `..`
|
||||
|
||||
fn foo_qualified<T: Trait>() where <T as Trait>::method(i32): Send {}
|
||||
//~^ ERROR expected associated type
|
||||
|
||||
fn bar_qualified<T: Trait>() where <T as Trait>::method() -> (): Send {}
|
||||
//~^ ERROR expected associated type
|
||||
|
||||
fn baz_qualified<T: Trait>() where <T as Trait>::method(): Send {}
|
||||
//~^ ERROR expected associated type
|
||||
|
||||
fn main() {}
|
||||
|
|
|
@ -1,3 +1,21 @@
|
|||
error[E0575]: expected associated type, found associated function `Trait::method`
|
||||
--> $DIR/bad-inputs-and-output.rs:28:36
|
||||
|
|
||||
LL | fn foo_qualified<T: Trait>() where <T as Trait>::method(i32): Send {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^ not a associated type
|
||||
|
||||
error[E0575]: expected associated type, found associated function `Trait::method`
|
||||
--> $DIR/bad-inputs-and-output.rs:31:36
|
||||
|
|
||||
LL | fn bar_qualified<T: Trait>() where <T as Trait>::method() -> (): Send {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not a associated type
|
||||
|
||||
error[E0575]: expected associated type, found associated function `Trait::method`
|
||||
--> $DIR/bad-inputs-and-output.rs:34:36
|
||||
|
|
||||
LL | fn baz_qualified<T: Trait>() where <T as Trait>::method(): Send {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^ not a associated type
|
||||
|
||||
warning: the feature `return_type_notation` is incomplete and may not be safe to use and/or cause compiler crashes
|
||||
--> $DIR/bad-inputs-and-output.rs:3:12
|
||||
|
|
||||
|
@ -25,5 +43,24 @@ error: return type notation arguments must be elided with `..`
|
|||
LL | fn baz<T: Trait<method(): Send>>() {}
|
||||
| ^^ help: add `..`: `(..)`
|
||||
|
||||
error: aborting due to 3 previous errors; 1 warning emitted
|
||||
error: argument types not allowed with return type notation
|
||||
--> $DIR/bad-inputs-and-output.rs:19:40
|
||||
|
|
||||
LL | fn foo_path<T: Trait>() where T::method(i32): Send {}
|
||||
| ^^^^^ help: remove the input types: `()`
|
||||
|
||||
error: return type not allowed with return type notation
|
||||
--> $DIR/bad-inputs-and-output.rs:22:42
|
||||
|
|
||||
LL | fn bar_path<T: Trait>() where T::method() -> (): Send {}
|
||||
| ^^^^^^ help: remove the return type
|
||||
|
||||
error: return type notation arguments must be elided with `..`
|
||||
--> $DIR/bad-inputs-and-output.rs:25:40
|
||||
|
|
||||
LL | fn baz_path<T: Trait>() where T::method(): Send {}
|
||||
| ^^ help: add `..`: `(..)`
|
||||
|
||||
error: aborting due to 9 previous errors; 1 warning emitted
|
||||
|
||||
For more information about this error, try `rustc --explain E0575`.
|
||||
|
|
|
@ -10,17 +10,12 @@ trait Tr {
|
|||
fn foo<T: Tr>()
|
||||
where
|
||||
T::method(..): Send,
|
||||
//~^ ERROR return type notation not allowed in this position yet
|
||||
//~| ERROR expected type, found function
|
||||
<T as Tr>::method(..): Send,
|
||||
//~^ ERROR return type notation not allowed in this position yet
|
||||
//~| ERROR expected associated type, found associated function `Tr::method`
|
||||
{
|
||||
let _ = T::CONST::(..);
|
||||
//~^ ERROR return type notation not allowed in this position yet
|
||||
let _: T::method(..);
|
||||
//~^ ERROR return type notation not allowed in this position yet
|
||||
//~| ERROR expected type, found function
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
|
|
@ -1,9 +1,3 @@
|
|||
error[E0575]: expected associated type, found associated function `Tr::method`
|
||||
--> $DIR/bare-path.rs:15:5
|
||||
|
|
||||
LL | <T as Tr>::method(..): Send,
|
||||
| ^^^^^^^^^^^^^^^^^^^^^ not a associated type
|
||||
|
||||
warning: the feature `return_type_notation` is incomplete and may not be safe to use and/or cause compiler crashes
|
||||
--> $DIR/bare-path.rs:1:12
|
||||
|
|
||||
|
@ -14,53 +8,16 @@ LL | #![feature(return_type_notation)]
|
|||
= note: `#[warn(incomplete_features)]` on by default
|
||||
|
||||
error: return type notation not allowed in this position yet
|
||||
--> $DIR/bare-path.rs:19:23
|
||||
--> $DIR/bare-path.rs:15:23
|
||||
|
|
||||
LL | let _ = T::CONST::(..);
|
||||
| ^^^^
|
||||
|
||||
error: return type notation not allowed in this position yet
|
||||
--> $DIR/bare-path.rs:21:21
|
||||
--> $DIR/bare-path.rs:17:12
|
||||
|
|
||||
LL | let _: T::method(..);
|
||||
| ^^^^
|
||||
| ^^^^^^^^^^^^^
|
||||
|
||||
error: return type notation not allowed in this position yet
|
||||
--> $DIR/bare-path.rs:12:14
|
||||
|
|
||||
LL | T::method(..): Send,
|
||||
| ^^^^
|
||||
error: aborting due to 2 previous errors; 1 warning emitted
|
||||
|
||||
error: return type notation not allowed in this position yet
|
||||
--> $DIR/bare-path.rs:15:22
|
||||
|
|
||||
LL | <T as Tr>::method(..): Send,
|
||||
| ^^^^
|
||||
|
||||
error: expected type, found function
|
||||
--> $DIR/bare-path.rs:12:8
|
||||
|
|
||||
LL | T::method(..): Send,
|
||||
| ^^^^^^ unexpected function
|
||||
|
|
||||
note: the associated function is defined here
|
||||
--> $DIR/bare-path.rs:7:5
|
||||
|
|
||||
LL | fn method() -> impl Sized;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: expected type, found function
|
||||
--> $DIR/bare-path.rs:21:15
|
||||
|
|
||||
LL | let _: T::method(..);
|
||||
| ^^^^^^ unexpected function
|
||||
|
|
||||
note: the associated function is defined here
|
||||
--> $DIR/bare-path.rs:7:5
|
||||
|
|
||||
LL | fn method() -> impl Sized;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to 7 previous errors; 1 warning emitted
|
||||
|
||||
For more information about this error, try `rustc --explain E0575`.
|
||||
|
|
|
@ -0,0 +1,52 @@
|
|||
//@ check-pass
|
||||
|
||||
#![feature(return_type_notation)]
|
||||
//~^ WARN the feature `return_type_notation` is incomplete
|
||||
|
||||
trait Trait<'a> {
|
||||
fn late<'b>(&'b self, _: &'a ()) -> impl Sized;
|
||||
fn early<'b: 'b>(&'b self, _: &'a ()) -> impl Sized;
|
||||
}
|
||||
|
||||
#[allow(refining_impl_trait_internal)]
|
||||
impl<'a> Trait<'a> for () {
|
||||
fn late<'b>(&'b self, _: &'a ()) -> i32 { 1 }
|
||||
fn early<'b: 'b>(&'b self, _: &'a ()) -> i32 { 1 }
|
||||
}
|
||||
|
||||
trait Other<'c> {}
|
||||
impl Other<'_> for i32 {}
|
||||
|
||||
fn test<T>(t: &T)
|
||||
where
|
||||
T: for<'a, 'c> Trait<'a, late(..): Other<'c>>,
|
||||
// which is basically:
|
||||
// for<'a, 'c> Trait<'a, for<'b> method<'b>: Other<'c>>,
|
||||
T: for<'a, 'c> Trait<'a, early(..): Other<'c>>,
|
||||
// which is basically:
|
||||
// for<'a, 'c> Trait<'a, for<'b> method<'b>: Other<'c>>,
|
||||
{
|
||||
is_other_impl(t.late(&()));
|
||||
is_other_impl(t.early(&()));
|
||||
}
|
||||
|
||||
fn test_path<T>(t: &T)
|
||||
where
|
||||
T: for<'a> Trait<'a>,
|
||||
for<'a, 'c> <T as Trait<'a>>::late(..): Other<'c>,
|
||||
// which is basically:
|
||||
// for<'a, 'b, 'c> <T as Trait<'a>>::method::<'b>: Other<'c>
|
||||
for<'a, 'c> <T as Trait<'a>>::early(..): Other<'c>,
|
||||
// which is basically:
|
||||
// for<'a, 'b, 'c> <T as Trait<'a>>::method::<'b>: Other<'c>
|
||||
{
|
||||
is_other_impl(t.late(&()));
|
||||
is_other_impl(t.early(&()));
|
||||
}
|
||||
|
||||
fn is_other_impl(_: impl for<'c> Other<'c>) {}
|
||||
|
||||
fn main() {
|
||||
test(&());
|
||||
test(&());
|
||||
}
|
|
@ -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/higher-ranked-bound-works.rs:3:12
|
||||
|
|
||||
LL | #![feature(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
|
||||
|
|
@ -0,0 +1,42 @@
|
|||
//@ check-pass
|
||||
|
||||
#![allow(non_camel_case_types)]
|
||||
#![feature(return_type_notation)]
|
||||
//~^ WARN the feature `return_type_notation` is incomplete
|
||||
|
||||
trait Foo {
|
||||
type test;
|
||||
|
||||
fn test() -> impl Bar;
|
||||
}
|
||||
|
||||
fn call_path<T: Foo>()
|
||||
where
|
||||
T::test(..): Bar,
|
||||
{
|
||||
}
|
||||
|
||||
fn call_bound<T: Foo<test(..): Bar>>() {}
|
||||
|
||||
trait Bar {}
|
||||
struct NotBar;
|
||||
struct YesBar;
|
||||
impl Bar for YesBar {}
|
||||
|
||||
impl Foo for () {
|
||||
type test = NotBar;
|
||||
|
||||
// Use refinement here so we can observe `YesBar: Bar`.
|
||||
#[allow(refining_impl_trait_internal)]
|
||||
fn test() -> YesBar {
|
||||
YesBar
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
// If `T::test(..)` resolved to the GAT (erroneously), then this would be
|
||||
// an error since `<() as Foo>::bar` -- the associated type -- does not
|
||||
// implement `Bar`, but the return type of the method does.
|
||||
call_path::<()>();
|
||||
call_bound::<()>();
|
||||
}
|
|
@ -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/namespace-conflict.rs:4:12
|
||||
|
|
||||
LL | #![feature(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
|
||||
|
|
@ -5,7 +5,10 @@ trait Trait {
|
|||
fn method() {}
|
||||
}
|
||||
|
||||
fn test<T: Trait<method(..): Send>>() {}
|
||||
//~^ ERROR return type notation used on function that is not `async` and does not return `impl Trait`
|
||||
fn bound<T: Trait<method(..): Send>>() {}
|
||||
//~^ ERROR return type notation used on function that is not `async` and does not return `impl Trait`
|
||||
|
||||
fn path<T>() where T: Trait, T::method(..): Send {}
|
||||
//~^ ERROR return type notation used on function that is not `async` and does not return `impl Trait`
|
||||
|
||||
fn main() {}
|
||||
|
|
|
@ -8,15 +8,26 @@ LL | #![feature(return_type_notation)]
|
|||
= note: `#[warn(incomplete_features)]` on by default
|
||||
|
||||
error: return type notation used on function that is not `async` and does not return `impl Trait`
|
||||
--> $DIR/non-rpitit.rs:8:18
|
||||
--> $DIR/non-rpitit.rs:8:19
|
||||
|
|
||||
LL | fn method() {}
|
||||
| ----------- this function must be `async` or return `impl Trait`
|
||||
...
|
||||
LL | fn test<T: Trait<method(..): Send>>() {}
|
||||
| ^^^^^^^^^^^^^^^^
|
||||
LL | fn bound<T: Trait<method(..): Send>>() {}
|
||||
| ^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: function returns `()`, which is not compatible with associated type return bounds
|
||||
|
||||
error: aborting due to 1 previous error; 1 warning emitted
|
||||
error: return type notation used on function that is not `async` and does not return `impl Trait`
|
||||
--> $DIR/non-rpitit.rs:11:30
|
||||
|
|
||||
LL | fn method() {}
|
||||
| ----------- this function must be `async` or return `impl Trait`
|
||||
...
|
||||
LL | fn path<T>() where T: Trait, T::method(..): Send {}
|
||||
| ^^^^^^^^^^^^^
|
||||
|
|
||||
= note: function returns `()`, which is not compatible with associated type return bounds
|
||||
|
||||
error: aborting due to 2 previous errors; 1 warning emitted
|
||||
|
||||
|
|
|
@ -0,0 +1,42 @@
|
|||
#![feature(return_type_notation)]
|
||||
//~^ WARN the feature `return_type_notation` is incomplete
|
||||
|
||||
fn function() {}
|
||||
|
||||
fn not_a_method()
|
||||
where
|
||||
function(..): Send,
|
||||
//~^ ERROR expected function, found function `function`
|
||||
//~| ERROR return type notation not allowed in this position yet
|
||||
{
|
||||
}
|
||||
|
||||
fn not_a_method_and_typoed()
|
||||
where
|
||||
function(): Send,
|
||||
//~^ ERROR expected type, found function `function`
|
||||
{
|
||||
}
|
||||
|
||||
trait Tr {
|
||||
fn method();
|
||||
}
|
||||
|
||||
// Forgot the `T::`
|
||||
fn maybe_method_overlaps<T: Tr>()
|
||||
where
|
||||
method(..): Send,
|
||||
//~^ ERROR cannot find function `method` in this scope
|
||||
//~| ERROR return type notation not allowed in this position yet
|
||||
{
|
||||
}
|
||||
|
||||
// Forgot the `T::`, AND typoed `(..)` to `()`
|
||||
fn maybe_method_overlaps_and_typoed<T: Tr>()
|
||||
where
|
||||
method(): Send,
|
||||
//~^ ERROR cannot find type `method` in this scope
|
||||
{
|
||||
}
|
||||
|
||||
fn main() {}
|
|
@ -0,0 +1,49 @@
|
|||
error[E0575]: expected function, found function `function`
|
||||
--> $DIR/not-a-method.rs:8:5
|
||||
|
|
||||
LL | function(..): Send,
|
||||
| ^^^^^^^^^^^^ not a function
|
||||
|
||||
error[E0573]: expected type, found function `function`
|
||||
--> $DIR/not-a-method.rs:16:5
|
||||
|
|
||||
LL | function(): Send,
|
||||
| ^^^^^^^^^^ not a type
|
||||
|
||||
error[E0576]: cannot find function `method` in this scope
|
||||
--> $DIR/not-a-method.rs:28:5
|
||||
|
|
||||
LL | method(..): Send,
|
||||
| ^^^^^^ not found in this scope
|
||||
|
||||
error[E0412]: cannot find type `method` in this scope
|
||||
--> $DIR/not-a-method.rs:37:5
|
||||
|
|
||||
LL | method(): Send,
|
||||
| ^^^^^^ not found in this scope
|
||||
|
||||
warning: the feature `return_type_notation` is incomplete and may not be safe to use and/or cause compiler crashes
|
||||
--> $DIR/not-a-method.rs:1:12
|
||||
|
|
||||
LL | #![feature(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
|
||||
|
||||
error: return type notation not allowed in this position yet
|
||||
--> $DIR/not-a-method.rs:8:5
|
||||
|
|
||||
LL | function(..): Send,
|
||||
| ^^^^^^^^^^^^
|
||||
|
||||
error: return type notation not allowed in this position yet
|
||||
--> $DIR/not-a-method.rs:28:5
|
||||
|
|
||||
LL | method(..): Send,
|
||||
| ^^^^^^^^^^
|
||||
|
||||
error: aborting due to 6 previous errors; 1 warning emitted
|
||||
|
||||
Some errors have detailed explanations: E0412, E0573, E0575, E0576.
|
||||
For more information about an error, try `rustc --explain E0412`.
|
|
@ -0,0 +1,27 @@
|
|||
#![feature(return_type_notation)]
|
||||
//~^ WARN the feature `return_type_notation` is incomplete
|
||||
|
||||
trait A {
|
||||
fn method() -> impl Sized;
|
||||
}
|
||||
trait B {
|
||||
fn method() -> impl Sized;
|
||||
}
|
||||
|
||||
fn ambiguous<T: A + B>()
|
||||
where
|
||||
T::method(..): Send,
|
||||
//~^ ERROR ambiguous associated function `method` in bounds of `T`
|
||||
{
|
||||
}
|
||||
|
||||
trait Sub: A + B {}
|
||||
|
||||
fn ambiguous_via_supertrait<T: Sub>()
|
||||
where
|
||||
T::method(..): Send,
|
||||
//~^ ERROR ambiguous associated function `method` in bounds of `T`
|
||||
{
|
||||
}
|
||||
|
||||
fn main() {}
|
|
@ -0,0 +1,54 @@
|
|||
warning: the feature `return_type_notation` is incomplete and may not be safe to use and/or cause compiler crashes
|
||||
--> $DIR/path-ambiguous.rs:1:12
|
||||
|
|
||||
LL | #![feature(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
|
||||
|
||||
error[E0221]: ambiguous associated function `method` in bounds of `T`
|
||||
--> $DIR/path-ambiguous.rs:13:5
|
||||
|
|
||||
LL | fn method() -> impl Sized;
|
||||
| -------------------------- ambiguous `method` from `A`
|
||||
...
|
||||
LL | fn method() -> impl Sized;
|
||||
| -------------------------- ambiguous `method` from `B`
|
||||
...
|
||||
LL | T::method(..): Send,
|
||||
| ^^^^^^^^^^^^^ ambiguous associated function `method`
|
||||
|
|
||||
help: use fully-qualified syntax to disambiguate
|
||||
|
|
||||
LL | <T as B>::method(..): Send,
|
||||
| ~~~~~~~~~~
|
||||
help: use fully-qualified syntax to disambiguate
|
||||
|
|
||||
LL | <T as A>::method(..): Send,
|
||||
| ~~~~~~~~~~
|
||||
|
||||
error[E0221]: ambiguous associated function `method` in bounds of `T`
|
||||
--> $DIR/path-ambiguous.rs:22:5
|
||||
|
|
||||
LL | fn method() -> impl Sized;
|
||||
| -------------------------- ambiguous `method` from `A`
|
||||
...
|
||||
LL | fn method() -> impl Sized;
|
||||
| -------------------------- ambiguous `method` from `B`
|
||||
...
|
||||
LL | T::method(..): Send,
|
||||
| ^^^^^^^^^^^^^ ambiguous associated function `method`
|
||||
|
|
||||
help: use fully-qualified syntax to disambiguate
|
||||
|
|
||||
LL | <T as B>::method(..): Send,
|
||||
| ~~~~~~~~~~
|
||||
help: use fully-qualified syntax to disambiguate
|
||||
|
|
||||
LL | <T as A>::method(..): Send,
|
||||
| ~~~~~~~~~~
|
||||
|
||||
error: aborting due to 2 previous errors; 1 warning emitted
|
||||
|
||||
For more information about this error, try `rustc --explain E0221`.
|
|
@ -0,0 +1,24 @@
|
|||
//@ check-pass
|
||||
|
||||
#![feature(return_type_notation)]
|
||||
//~^ WARN the feature `return_type_notation` is incomplete
|
||||
|
||||
trait Trait {
|
||||
fn method() -> impl Sized;
|
||||
}
|
||||
|
||||
fn is_send(_: impl Send) {}
|
||||
|
||||
struct W<T>(T);
|
||||
|
||||
impl<T> W<T> {
|
||||
fn test()
|
||||
where
|
||||
T: Trait,
|
||||
T::method(..): Send,
|
||||
{
|
||||
is_send(T::method());
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {}
|
|
@ -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/path-constrained-in-method.rs:3:12
|
||||
|
|
||||
LL | #![feature(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
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
#![feature(return_type_notation)]
|
||||
//~^ WARN the feature `return_type_notation` is incomplete
|
||||
|
||||
trait A<'a> {
|
||||
fn method() -> impl Sized;
|
||||
}
|
||||
trait B: for<'a> A<'a> {}
|
||||
|
||||
fn higher_ranked<T>()
|
||||
where
|
||||
T: for<'a> A<'a>,
|
||||
T::method(..): Send,
|
||||
//~^ ERROR cannot use the associated function of a trait with uninferred generic parameters
|
||||
{
|
||||
}
|
||||
|
||||
fn higher_ranked_via_supertrait<T>()
|
||||
where
|
||||
T: B,
|
||||
T::method(..): Send,
|
||||
//~^ ERROR cannot use the associated function of a trait with uninferred generic parameters
|
||||
{
|
||||
}
|
||||
|
||||
fn main() {}
|
|
@ -0,0 +1,34 @@
|
|||
warning: the feature `return_type_notation` is incomplete and may not be safe to use and/or cause compiler crashes
|
||||
--> $DIR/path-higher-ranked.rs:1:12
|
||||
|
|
||||
LL | #![feature(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
|
||||
|
||||
error[E0212]: cannot use the associated function of a trait with uninferred generic parameters
|
||||
--> $DIR/path-higher-ranked.rs:12:5
|
||||
|
|
||||
LL | T::method(..): Send,
|
||||
| ^^^^^^^^^^^^^
|
||||
|
|
||||
help: use a fully qualified path with inferred lifetimes
|
||||
|
|
||||
LL | <T as A<'_>>::method(..): Send,
|
||||
| ~~~~~~~~~~~~~~
|
||||
|
||||
error[E0212]: cannot use the associated function of a trait with uninferred generic parameters
|
||||
--> $DIR/path-higher-ranked.rs:20:5
|
||||
|
|
||||
LL | T::method(..): Send,
|
||||
| ^^^^^^^^^^^^^
|
||||
|
|
||||
help: use a fully qualified path with inferred lifetimes
|
||||
|
|
||||
LL | <T as A<'_>>::method(..): Send,
|
||||
| ~~~~~~~~~~~~~~
|
||||
|
||||
error: aborting due to 2 previous errors; 1 warning emitted
|
||||
|
||||
For more information about this error, try `rustc --explain E0212`.
|
|
@ -0,0 +1,25 @@
|
|||
#![feature(return_type_notation)]
|
||||
//~^ WARN the feature `return_type_notation` is incomplete
|
||||
|
||||
trait A {
|
||||
#[allow(non_camel_case_types)]
|
||||
type bad;
|
||||
}
|
||||
|
||||
fn fully_qualified<T: A>()
|
||||
where
|
||||
<T as A>::method(..): Send,
|
||||
//~^ ERROR cannot find method or associated constant `method` in trait `A`
|
||||
<T as A>::bad(..): Send,
|
||||
//~^ ERROR expected method or associated constant, found associated type `A::bad`
|
||||
{
|
||||
}
|
||||
|
||||
fn type_dependent<T: A>()
|
||||
where
|
||||
T::method(..): Send,
|
||||
//~^ associated function `method` not found for `T`
|
||||
{
|
||||
}
|
||||
|
||||
fn main() {}
|
|
@ -0,0 +1,33 @@
|
|||
error[E0576]: cannot find method or associated constant `method` in trait `A`
|
||||
--> $DIR/path-missing.rs:11:15
|
||||
|
|
||||
LL | <T as A>::method(..): Send,
|
||||
| ^^^^^^ not found in `A`
|
||||
|
||||
error[E0575]: expected method or associated constant, found associated type `A::bad`
|
||||
--> $DIR/path-missing.rs:13:5
|
||||
|
|
||||
LL | <T as A>::bad(..): Send,
|
||||
| ^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: can't use a type alias as a constructor
|
||||
|
||||
warning: the feature `return_type_notation` is incomplete and may not be safe to use and/or cause compiler crashes
|
||||
--> $DIR/path-missing.rs:1:12
|
||||
|
|
||||
LL | #![feature(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
|
||||
|
||||
error[E0220]: associated function `method` not found for `T`
|
||||
--> $DIR/path-missing.rs:20:8
|
||||
|
|
||||
LL | T::method(..): Send,
|
||||
| ^^^^^^ associated function `method` not found
|
||||
|
||||
error: aborting due to 3 previous errors; 1 warning emitted
|
||||
|
||||
Some errors have detailed explanations: E0220, E0575, E0576.
|
||||
For more information about an error, try `rustc --explain E0220`.
|
|
@ -0,0 +1,15 @@
|
|||
#![feature(return_type_notation)]
|
||||
//~^ WARN the feature `return_type_notation` is incomplete
|
||||
|
||||
trait Trait {
|
||||
fn method() -> impl Sized;
|
||||
}
|
||||
|
||||
fn test()
|
||||
where
|
||||
Trait::method(..): Send,
|
||||
//~^ ERROR ambiguous associated type
|
||||
{
|
||||
}
|
||||
|
||||
fn main() {}
|
|
@ -0,0 +1,23 @@
|
|||
warning: the feature `return_type_notation` is incomplete and may not be safe to use and/or cause compiler crashes
|
||||
--> $DIR/path-no-qself.rs:1:12
|
||||
|
|
||||
LL | #![feature(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
|
||||
|
||||
error[E0223]: ambiguous associated type
|
||||
--> $DIR/path-no-qself.rs:10:5
|
||||
|
|
||||
LL | Trait::method(..): Send,
|
||||
| ^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
help: if there were a type named `Example` that implemented `Trait`, you could use the fully-qualified path
|
||||
|
|
||||
LL | <Example as Trait>::method: Send,
|
||||
| ~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
error: aborting due to 1 previous error; 1 warning emitted
|
||||
|
||||
For more information about this error, try `rustc --explain E0223`.
|
|
@ -0,0 +1,21 @@
|
|||
#![feature(return_type_notation)]
|
||||
//~^ WARN the feature `return_type_notation` is incomplete
|
||||
|
||||
trait Trait {
|
||||
fn method() -> impl Sized;
|
||||
}
|
||||
|
||||
struct Adt;
|
||||
|
||||
fn non_param_qself()
|
||||
where
|
||||
<()>::method(..): Send,
|
||||
//~^ ERROR ambiguous associated function
|
||||
i32::method(..): Send,
|
||||
//~^ ERROR ambiguous associated function
|
||||
Adt::method(..): Send,
|
||||
//~^ ERROR ambiguous associated function
|
||||
{
|
||||
}
|
||||
|
||||
fn main() {}
|
|
@ -0,0 +1,30 @@
|
|||
warning: the feature `return_type_notation` is incomplete and may not be safe to use and/or cause compiler crashes
|
||||
--> $DIR/path-non-param-qself.rs:1:12
|
||||
|
|
||||
LL | #![feature(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
|
||||
|
||||
error[E0223]: ambiguous associated function
|
||||
--> $DIR/path-non-param-qself.rs:12:5
|
||||
|
|
||||
LL | <()>::method(..): Send,
|
||||
| ^^^^^^^^^^^^^^^^
|
||||
|
||||
error[E0223]: ambiguous associated function
|
||||
--> $DIR/path-non-param-qself.rs:14:5
|
||||
|
|
||||
LL | i32::method(..): Send,
|
||||
| ^^^^^^^^^^^^^^^
|
||||
|
||||
error[E0223]: ambiguous associated function
|
||||
--> $DIR/path-non-param-qself.rs:16:5
|
||||
|
|
||||
LL | Adt::method(..): Send,
|
||||
| ^^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to 3 previous errors; 1 warning emitted
|
||||
|
||||
For more information about this error, try `rustc --explain E0223`.
|
|
@ -0,0 +1,27 @@
|
|||
//@ check-pass
|
||||
|
||||
#![feature(return_type_notation)]
|
||||
//~^ WARN the feature `return_type_notation` is incomplete
|
||||
|
||||
trait Foo {
|
||||
fn method() -> impl Sized;
|
||||
}
|
||||
|
||||
trait Bar: Foo {
|
||||
fn other()
|
||||
where
|
||||
Self::method(..): Send;
|
||||
}
|
||||
|
||||
fn is_send(_: impl Send) {}
|
||||
|
||||
impl<T: Foo> Bar for T {
|
||||
fn other()
|
||||
where
|
||||
Self::method(..): Send,
|
||||
{
|
||||
is_send(Self::method());
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {}
|
|
@ -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/path-self-qself.rs:3:12
|
||||
|
|
||||
LL | #![feature(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
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
#![feature(return_type_notation)]
|
||||
//~^ WARN the feature `return_type_notation` is incomplete
|
||||
|
||||
trait Foo {
|
||||
fn method<T>() -> impl Sized;
|
||||
}
|
||||
|
||||
fn test<T: Foo>()
|
||||
where
|
||||
<T as Foo>::method(..): Send,
|
||||
//~^ ERROR return type notation is not allowed for functions that have type parameters
|
||||
{
|
||||
}
|
||||
|
||||
fn test_type_dependent<T: Foo>()
|
||||
where
|
||||
<T as Foo>::method(..): Send,
|
||||
//~^ ERROR return type notation is not allowed for functions that have type parameters
|
||||
{
|
||||
}
|
||||
|
||||
fn main() {}
|
|
@ -0,0 +1,29 @@
|
|||
warning: the feature `return_type_notation` is incomplete and may not be safe to use and/or cause compiler crashes
|
||||
--> $DIR/path-type-param.rs:1:12
|
||||
|
|
||||
LL | #![feature(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
|
||||
|
||||
error: return type notation is not allowed for functions that have type parameters
|
||||
--> $DIR/path-type-param.rs:10:5
|
||||
|
|
||||
LL | fn method<T>() -> impl Sized;
|
||||
| - type parameter declared here
|
||||
...
|
||||
LL | <T as Foo>::method(..): Send,
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: return type notation is not allowed for functions that have type parameters
|
||||
--> $DIR/path-type-param.rs:17:5
|
||||
|
|
||||
LL | fn method<T>() -> impl Sized;
|
||||
| - type parameter declared here
|
||||
...
|
||||
LL | <T as Foo>::method(..): Send,
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to 2 previous errors; 1 warning emitted
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
#![feature(return_type_notation)]
|
||||
//~^ WARN the feature `return_type_notation` is incomplete
|
||||
|
||||
trait Trait {
|
||||
fn method() -> impl Sized;
|
||||
}
|
||||
|
||||
struct DoesntWork;
|
||||
impl Trait for DoesntWork {
|
||||
fn method() -> impl Sized {
|
||||
std::ptr::null_mut::<()>()
|
||||
// This isn't `Send`.
|
||||
}
|
||||
}
|
||||
|
||||
fn test<T: Trait>()
|
||||
where
|
||||
T::method(..): Send,
|
||||
{
|
||||
}
|
||||
|
||||
fn main() {
|
||||
test::<DoesntWork>();
|
||||
//~^ ERROR `*mut ()` cannot be sent between threads safely
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
warning: the feature `return_type_notation` is incomplete and may not be safe to use and/or cause compiler crashes
|
||||
--> $DIR/path-unsatisfied.rs:1:12
|
||||
|
|
||||
LL | #![feature(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
|
||||
|
||||
error[E0277]: `*mut ()` cannot be sent between threads safely
|
||||
--> $DIR/path-unsatisfied.rs:23:12
|
||||
|
|
||||
LL | fn method() -> impl Sized {
|
||||
| ---------- within this `impl Sized`
|
||||
...
|
||||
LL | test::<DoesntWork>();
|
||||
| ^^^^^^^^^^ `*mut ()` cannot be sent between threads safely
|
||||
|
|
||||
= help: within `impl Sized`, the trait `Send` is not implemented for `*mut ()`, which is required by `impl Sized: Send`
|
||||
note: required because it appears within the type `impl Sized`
|
||||
--> $DIR/path-unsatisfied.rs:10:20
|
||||
|
|
||||
LL | fn method() -> impl Sized {
|
||||
| ^^^^^^^^^^
|
||||
note: required by a bound in `test`
|
||||
--> $DIR/path-unsatisfied.rs:18:20
|
||||
|
|
||||
LL | fn test<T: Trait>()
|
||||
| ---- required by a bound in this function
|
||||
LL | where
|
||||
LL | T::method(..): Send,
|
||||
| ^^^^ required by this bound in `test`
|
||||
|
||||
error: aborting due to 1 previous error; 1 warning emitted
|
||||
|
||||
For more information about this error, try `rustc --explain E0277`.
|
|
@ -0,0 +1,23 @@
|
|||
//@ check-pass
|
||||
|
||||
#![feature(return_type_notation)]
|
||||
//~^ WARN the feature `return_type_notation` is incomplete
|
||||
|
||||
trait Trait {
|
||||
fn method() -> impl Sized;
|
||||
}
|
||||
|
||||
struct Works;
|
||||
impl Trait for Works {
|
||||
fn method() -> impl Sized {}
|
||||
}
|
||||
|
||||
fn test<T: Trait>()
|
||||
where
|
||||
T::method(..): Send,
|
||||
{
|
||||
}
|
||||
|
||||
fn main() {
|
||||
test::<Works>();
|
||||
}
|
|
@ -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/path-works.rs:3:12
|
||||
|
|
||||
LL | #![feature(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
|
||||
|
|
@ -1,8 +1,8 @@
|
|||
pub fn foo(num: i32) -> i32 {
|
||||
let foo: i32::from_be(num);
|
||||
//~^ ERROR expected type, found local variable `num`
|
||||
//~| ERROR parenthesized type parameters may only be used with a `Fn` trait
|
||||
//~| ERROR ambiguous associated type
|
||||
//~| ERROR argument types not allowed with return type notation
|
||||
//~| ERROR return type notation not allowed in this position yet
|
||||
foo
|
||||
}
|
||||
|
||||
|
|
|
@ -6,29 +6,22 @@ LL | let foo: i32::from_be(num);
|
|||
| |
|
||||
| help: use `=` if you meant to assign
|
||||
|
||||
error[E0214]: parenthesized type parameters may only be used with a `Fn` trait
|
||||
--> $DIR/let-binding-init-expr-as-ty.rs:2:19
|
||||
error: argument types not allowed with return type notation
|
||||
--> $DIR/let-binding-init-expr-as-ty.rs:2:26
|
||||
|
|
||||
LL | let foo: i32::from_be(num);
|
||||
| ^^^^^^^^^^^^ only `Fn` traits may use parentheses
|
||||
| ^^^^^ help: remove the input types: `()`
|
||||
|
|
||||
help: use angle brackets instead
|
||||
|
|
||||
LL | let foo: i32::from_be<num>;
|
||||
| ~ ~
|
||||
= note: see issue #109417 <https://github.com/rust-lang/rust/issues/109417> for more information
|
||||
= help: add `#![feature(return_type_notation)]` to the crate attributes to enable
|
||||
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
|
||||
|
||||
error[E0223]: ambiguous associated type
|
||||
error: return type notation not allowed in this position yet
|
||||
--> $DIR/let-binding-init-expr-as-ty.rs:2:14
|
||||
|
|
||||
LL | let foo: i32::from_be(num);
|
||||
| ^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
help: if there were a trait named `Example` with associated type `from_be` implemented for `i32`, you could use the fully-qualified path
|
||||
|
|
||||
LL | let foo: <i32 as Example>::from_be;
|
||||
| ~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
|
||||
Some errors have detailed explanations: E0214, E0223, E0573.
|
||||
For more information about an error, try `rustc --explain E0214`.
|
||||
For more information about this error, try `rustc --explain E0573`.
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue