mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-22 06:44:35 +00:00
Implement RTN in resolve_bound_vars and HIR ty lowering
This commit is contained in:
parent
19881b5a5a
commit
51b51bb570
@ -487,11 +487,12 @@ enum ParamMode {
|
||||
|
||||
#[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,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
enum GenericArgsMode {
|
||||
ParenSugar,
|
||||
ReturnTypeNotation,
|
||||
@ -1239,7 +1240,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
qself,
|
||||
path,
|
||||
param_mode,
|
||||
// We deny these after the fact in HIR->middle type lowering.
|
||||
AllowReturnTypeNotation::Yes,
|
||||
itctx,
|
||||
None,
|
||||
|
@ -16,10 +16,9 @@ use super::errors::{
|
||||
GenericTypeWithParentheses, UseAngleBrackets,
|
||||
};
|
||||
use super::{
|
||||
AllowReturnTypeNotation, 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))]
|
||||
|
@ -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
|
||||
@ -1839,6 +1844,110 @@ 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));
|
||||
}
|
||||
|
||||
// TODO:
|
||||
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 {
|
||||
// TODO:
|
||||
return;
|
||||
};
|
||||
|
||||
let (mut bound_vars, item_def_id, item_segment) = match qpath {
|
||||
// TODO:
|
||||
hir::QPath::Resolved(_, path)
|
||||
if let [.., item_segment] = &path.segments[..]
|
||||
&& item_segment.args.is_some_and(|args| {
|
||||
matches!(
|
||||
args.parenthesized,
|
||||
hir::GenericArgsParentheses::ReturnTypeNotation
|
||||
)
|
||||
}) =>
|
||||
{
|
||||
let Res::Def(DefKind::AssocFn, item_def_id) = path.res else {
|
||||
bug!();
|
||||
};
|
||||
(vec![], item_def_id, item_segment)
|
||||
}
|
||||
|
||||
// TODO:
|
||||
hir::QPath::TypeRelative(qself, item_segment)
|
||||
if item_segment.args.is_some_and(|args| {
|
||||
matches!(args.parenthesized, hir::GenericArgsParentheses::ReturnTypeNotation)
|
||||
}) =>
|
||||
{
|
||||
let hir::TyKind::Path(hir::QPath::Resolved(None, path)) = qself.kind else {
|
||||
return;
|
||||
};
|
||||
|
||||
match path.res {
|
||||
Res::Def(DefKind::TyParam, _) | Res::SelfTyParam { trait_: _ } => {
|
||||
let Some(generics) = self.tcx.hir_owner_node(hir_id.owner).generics()
|
||||
else {
|
||||
return;
|
||||
};
|
||||
|
||||
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)
|
||||
}
|
||||
Res::SelfTyAlias { is_trait_impl: true, .. } => todo!(),
|
||||
_ => return,
|
||||
}
|
||||
}
|
||||
|
||||
_ => return,
|
||||
};
|
||||
|
||||
// TODO:
|
||||
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());
|
||||
|
||||
// TODO:
|
||||
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);
|
||||
// TODO: subtle
|
||||
self.record_late_bound_vars(item_segment.hir_id, existing_bound_vars_saved);
|
||||
}
|
||||
}
|
||||
|
||||
/// Detects late-bound lifetimes and inserts them into
|
||||
|
@ -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,219 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// TODO:
|
||||
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
|
||||
)
|
||||
}) =>
|
||||
{
|
||||
let _ =
|
||||
self.prohibit_generic_args(mod_segments.iter(), GenericsArgsErrExtend::None);
|
||||
|
||||
let Res::Def(DefKind::AssocFn, item_def_id) = path.res else {
|
||||
bug!();
|
||||
};
|
||||
let trait_def_id = tcx.parent(item_def_id);
|
||||
|
||||
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,
|
||||
);
|
||||
|
||||
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),
|
||||
}
|
||||
}
|
||||
|
||||
// TODO:
|
||||
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,
|
||||
)?,
|
||||
_ => todo!(),
|
||||
};
|
||||
|
||||
// Don't let `T::method` resolve to some `for<'a> <T as Tr<'a>>::method`.
|
||||
// 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`.
|
||||
if bound.has_bound_vars() {
|
||||
todo!();
|
||||
}
|
||||
|
||||
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))
|
||||
}
|
||||
|
||||
// TODO:
|
||||
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.
|
||||
|
@ -820,10 +820,11 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
||||
///
|
||||
/// `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 +842,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 +1082,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,6 +1547,27 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
||||
debug!(?trait_def_id);
|
||||
|
||||
let Some(self_ty) = opt_self_ty else {
|
||||
return self.error_missing_qpath_self_ty(trait_def_id, span, item_segment);
|
||||
};
|
||||
debug!(?self_ty);
|
||||
|
||||
let trait_ref =
|
||||
self.lower_mono_trait_ref(span, trait_def_id, self_ty, trait_segment, false, constness);
|
||||
debug!(?trait_ref);
|
||||
|
||||
let item_args =
|
||||
self.lower_generic_args_of_assoc_item(span, item_def_id, item_segment, trait_ref.args);
|
||||
|
||||
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();
|
||||
@ -1580,24 +1603,9 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
||||
// 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);
|
||||
};
|
||||
debug!(?self_ty);
|
||||
|
||||
let trait_ref =
|
||||
self.lower_mono_trait_ref(span, trait_def_id, self_ty, trait_segment, false, constness);
|
||||
debug!(?trait_ref);
|
||||
|
||||
let item_args =
|
||||
self.lower_generic_args_of_assoc_item(span, item_def_id, item_segment, trait_ref.args);
|
||||
|
||||
Ty::new_projection_from_args(tcx, item_def_id, item_args)
|
||||
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>(
|
||||
@ -1910,19 +1918,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
||||
ty::BoundConstness::NotConst,
|
||||
)
|
||||
}
|
||||
// Deny any qpath types that were successfully lowered in AST lowering.
|
||||
Res::Def(DefKind::AssocFn, _)
|
||||
if let [.., _trait_segment, item_segment] = &path.segments[..]
|
||||
&& item_segment.args.is_some_and(|args| {
|
||||
matches!(
|
||||
args.parenthesized,
|
||||
hir::GenericArgsParentheses::ReturnTypeNotation
|
||||
)
|
||||
}) =>
|
||||
{
|
||||
let guar = self.dcx().emit_err(BadReturnTypeNotation { span: path.span });
|
||||
Ty::new_error(tcx, guar)
|
||||
}
|
||||
Res::PrimTy(prim_ty) => {
|
||||
assert_eq!(opt_self_ty, None);
|
||||
let _ = self.prohibit_generic_args(
|
||||
@ -1943,7 +1938,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!(
|
||||
@ -2098,6 +2093,15 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
||||
ref i => bug!("`impl Trait` pointed to non-opaque type?? {:#?}", i),
|
||||
}
|
||||
}
|
||||
// TODO:
|
||||
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);
|
||||
|
@ -790,6 +790,7 @@ impl<'ra: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'_, 'ast, 'r
|
||||
TyKind::Path(qself, path) => {
|
||||
self.diag_metadata.current_type_path = Some(ty);
|
||||
|
||||
// TODO:
|
||||
let source = if let Some(seg) = path.segments.last()
|
||||
&& let Some(args) = &seg.args
|
||||
&& matches!(**args, GenericArgs::ParenthesizedElided(..))
|
||||
|
@ -10,14 +10,12 @@ trait Tr {
|
||||
fn foo<T: Tr>()
|
||||
where
|
||||
T::method(..): Send,
|
||||
//~^ ERROR expected type, found function
|
||||
<T as Tr>::method(..): Send,
|
||||
//~^ ERROR return type notation not allowed in this position yet
|
||||
{
|
||||
let _ = T::CONST::(..);
|
||||
//~^ ERROR return type notation not allowed in this position yet
|
||||
let _: T::method(..);
|
||||
//~^ ERROR expected type, found function
|
||||
//~^ ERROR return type notation not allowed in this position yet
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
@ -8,40 +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:17:23
|
||||
--> $DIR/bare-path.rs:15:23
|
||||
|
|
||||
LL | let _ = T::CONST::(..);
|
||||
| ^^^^
|
||||
|
||||
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: return type notation not allowed in this position yet
|
||||
--> $DIR/bare-path.rs:14:5
|
||||
|
|
||||
LL | <T as Tr>::method(..): Send,
|
||||
| ^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: expected type, found function
|
||||
--> $DIR/bare-path.rs:19:15
|
||||
--> $DIR/bare-path.rs:17:12
|
||||
|
|
||||
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 4 previous errors; 1 warning emitted
|
||||
error: aborting due to 2 previous errors; 1 warning emitted
|
||||
|
||||
|
@ -2,7 +2,7 @@ pub fn foo(num: i32) -> i32 {
|
||||
let foo: i32::from_be(num);
|
||||
//~^ ERROR expected type, found local variable `num`
|
||||
//~| ERROR argument types not allowed with return type notation
|
||||
//~| ERROR ambiguous associated type
|
||||
//~| ERROR return type notation not allowed in this position yet
|
||||
foo
|
||||
}
|
||||
|
||||
|
@ -16,18 +16,12 @@ LL | let foo: i32::from_be(num);
|
||||
= 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: E0223, E0573.
|
||||
For more information about an error, try `rustc --explain E0223`.
|
||||
For more information about this error, try `rustc --explain E0573`.
|
||||
|
Loading…
Reference in New Issue
Block a user