Auto merge of #135057 - compiler-errors:project-unconstrained, r=oli-obk
Project to `TyKind::Error` when there are unconstrained non-lifetime (ty/const) impl params It splits the `enforce_impl_params_are_constrained` function into lifetime/non-lifetime, and queryfies the latter. We can then use the result of the latter query (`Result<(), ErrorGuaranteed>`) to intercept projection and constrain the projected type to `TyKind::Error`, which ensures that we leak no ty or const vars to places that don't expect them, like `normalize_erasing_regions`. The reason we split `enforce_impl_params_are_constrained` into two parts is because we only error for *lifetimes* if the lifetime ends up showing up in any of the associated types of the impl (e.g. we allow `impl<'a> Foo { type Assoc = (); }`). However, in order to compute the `type_of` query for the anonymous associated type of an RPITIT, we need to do trait solving (in `query collect_return_position_impl_trait_in_trait_tys`). That would induce cycles. Luckily, it turns out for lifetimes we don't even care about if they're unconstrained, since they're erased in all contexts that we are trying to fix ICEs. So it's sufficient to keep this check separated out of the query. I think this is a bit less invasive of an approach compared to #127973. The major difference between this PR and that PR is that we queryify the check instead of merging it into the `explicit_predicates_of` query, and we use the result to taint just projection goals, rather than trait goals too. This doesn't require a lot of new tracking in `ItemCtxt` and `GenericPredicates`, and it also seems to not require any other changes to typeck like that PR did. Fixes #123141 Fixes #125874 Fixes #126942 Fixes #127804 Fixes #130967 r? oli-obk
This commit is contained in:
commit
7349f6b503
32 changed files with 269 additions and 304 deletions
|
@ -57,22 +57,24 @@ pub(crate) fn check_impl_wf(
|
||||||
tcx: TyCtxt<'_>,
|
tcx: TyCtxt<'_>,
|
||||||
impl_def_id: LocalDefId,
|
impl_def_id: LocalDefId,
|
||||||
) -> Result<(), ErrorGuaranteed> {
|
) -> Result<(), ErrorGuaranteed> {
|
||||||
let min_specialization = tcx.features().min_specialization();
|
|
||||||
let mut res = Ok(());
|
|
||||||
debug_assert_matches!(tcx.def_kind(impl_def_id), DefKind::Impl { .. });
|
debug_assert_matches!(tcx.def_kind(impl_def_id), DefKind::Impl { .. });
|
||||||
res = res.and(enforce_impl_params_are_constrained(tcx, impl_def_id));
|
|
||||||
if min_specialization {
|
// Check that the args are constrained. We queryfied the check for ty/const params
|
||||||
|
// since unconstrained type/const params cause ICEs in projection, so we want to
|
||||||
|
// detect those specifically and project those to `TyKind::Error`.
|
||||||
|
let mut res = tcx.ensure().enforce_impl_non_lifetime_params_are_constrained(impl_def_id);
|
||||||
|
res = res.and(enforce_impl_lifetime_params_are_constrained(tcx, impl_def_id));
|
||||||
|
|
||||||
|
if tcx.features().min_specialization() {
|
||||||
res = res.and(check_min_specialization(tcx, impl_def_id));
|
res = res.and(check_min_specialization(tcx, impl_def_id));
|
||||||
}
|
}
|
||||||
|
|
||||||
res
|
res
|
||||||
}
|
}
|
||||||
|
|
||||||
fn enforce_impl_params_are_constrained(
|
pub(crate) fn enforce_impl_lifetime_params_are_constrained(
|
||||||
tcx: TyCtxt<'_>,
|
tcx: TyCtxt<'_>,
|
||||||
impl_def_id: LocalDefId,
|
impl_def_id: LocalDefId,
|
||||||
) -> Result<(), ErrorGuaranteed> {
|
) -> Result<(), ErrorGuaranteed> {
|
||||||
// Every lifetime used in an associated type must be constrained.
|
|
||||||
let impl_self_ty = tcx.type_of(impl_def_id).instantiate_identity();
|
let impl_self_ty = tcx.type_of(impl_def_id).instantiate_identity();
|
||||||
if impl_self_ty.references_error() {
|
if impl_self_ty.references_error() {
|
||||||
// Don't complain about unconstrained type params when self ty isn't known due to errors.
|
// Don't complain about unconstrained type params when self ty isn't known due to errors.
|
||||||
|
@ -88,6 +90,7 @@ fn enforce_impl_params_are_constrained(
|
||||||
// Compilation must continue in order for other important diagnostics to keep showing up.
|
// Compilation must continue in order for other important diagnostics to keep showing up.
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
let impl_generics = tcx.generics_of(impl_def_id);
|
let impl_generics = tcx.generics_of(impl_def_id);
|
||||||
let impl_predicates = tcx.predicates_of(impl_def_id);
|
let impl_predicates = tcx.predicates_of(impl_def_id);
|
||||||
let impl_trait_ref = tcx.impl_trait_ref(impl_def_id).map(ty::EarlyBinder::instantiate_identity);
|
let impl_trait_ref = tcx.impl_trait_ref(impl_def_id).map(ty::EarlyBinder::instantiate_identity);
|
||||||
|
@ -123,37 +126,22 @@ fn enforce_impl_params_are_constrained(
|
||||||
|
|
||||||
let mut res = Ok(());
|
let mut res = Ok(());
|
||||||
for param in &impl_generics.own_params {
|
for param in &impl_generics.own_params {
|
||||||
let err = match param.kind {
|
match param.kind {
|
||||||
// Disallow ANY unconstrained type parameters.
|
|
||||||
ty::GenericParamDefKind::Type { .. } => {
|
|
||||||
let param_ty = ty::ParamTy::for_def(param);
|
|
||||||
!input_parameters.contains(&cgp::Parameter::from(param_ty))
|
|
||||||
}
|
|
||||||
ty::GenericParamDefKind::Lifetime => {
|
ty::GenericParamDefKind::Lifetime => {
|
||||||
let param_lt = cgp::Parameter::from(param.to_early_bound_region_data());
|
let param_lt = cgp::Parameter::from(param.to_early_bound_region_data());
|
||||||
lifetimes_in_associated_types.contains(¶m_lt) && // (*)
|
if lifetimes_in_associated_types.contains(¶m_lt) // (*)
|
||||||
!input_parameters.contains(¶m_lt)
|
&& !input_parameters.contains(¶m_lt)
|
||||||
}
|
{
|
||||||
ty::GenericParamDefKind::Const { .. } => {
|
|
||||||
let param_ct = ty::ParamConst::for_def(param);
|
|
||||||
!input_parameters.contains(&cgp::Parameter::from(param_ct))
|
|
||||||
}
|
|
||||||
};
|
|
||||||
if err {
|
|
||||||
let const_param_note = matches!(param.kind, ty::GenericParamDefKind::Const { .. });
|
|
||||||
let mut diag = tcx.dcx().create_err(UnconstrainedGenericParameter {
|
let mut diag = tcx.dcx().create_err(UnconstrainedGenericParameter {
|
||||||
span: tcx.def_span(param.def_id),
|
span: tcx.def_span(param.def_id),
|
||||||
param_name: param.name,
|
param_name: param.name,
|
||||||
param_def_kind: tcx.def_descr(param.def_id),
|
param_def_kind: tcx.def_descr(param.def_id),
|
||||||
const_param_note,
|
const_param_note: false,
|
||||||
const_param_note2: const_param_note,
|
const_param_note2: false,
|
||||||
});
|
});
|
||||||
diag.code(E0207);
|
diag.code(E0207);
|
||||||
res = Err(diag.emit());
|
res = Err(diag.emit());
|
||||||
}
|
}
|
||||||
}
|
|
||||||
res
|
|
||||||
|
|
||||||
// (*) This is a horrible concession to reality. I think it'd be
|
// (*) This is a horrible concession to reality. I think it'd be
|
||||||
// better to just ban unconstrained lifetimes outright, but in
|
// better to just ban unconstrained lifetimes outright, but in
|
||||||
// practice people do non-hygienic macros like:
|
// practice people do non-hygienic macros like:
|
||||||
|
@ -173,3 +161,76 @@ fn enforce_impl_params_are_constrained(
|
||||||
// associated types. I believe this is sound, because lifetimes
|
// associated types. I believe this is sound, because lifetimes
|
||||||
// used elsewhere are not projected back out.
|
// used elsewhere are not projected back out.
|
||||||
}
|
}
|
||||||
|
ty::GenericParamDefKind::Type { .. } | ty::GenericParamDefKind::Const { .. } => {
|
||||||
|
// Enforced in `enforce_impl_non_lifetime_params_are_constrained`.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
res
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn enforce_impl_non_lifetime_params_are_constrained(
|
||||||
|
tcx: TyCtxt<'_>,
|
||||||
|
impl_def_id: LocalDefId,
|
||||||
|
) -> Result<(), ErrorGuaranteed> {
|
||||||
|
let impl_self_ty = tcx.type_of(impl_def_id).instantiate_identity();
|
||||||
|
if impl_self_ty.references_error() {
|
||||||
|
// Don't complain about unconstrained type params when self ty isn't known due to errors.
|
||||||
|
// (#36836)
|
||||||
|
tcx.dcx().span_delayed_bug(
|
||||||
|
tcx.def_span(impl_def_id),
|
||||||
|
format!(
|
||||||
|
"potentially unconstrained type parameters weren't evaluated: {impl_self_ty:?}",
|
||||||
|
),
|
||||||
|
);
|
||||||
|
// This is super fishy, but our current `rustc_hir_analysis::check_crate` pipeline depends on
|
||||||
|
// `type_of` having been called much earlier, and thus this value being read from cache.
|
||||||
|
// Compilation must continue in order for other important diagnostics to keep showing up.
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
let impl_generics = tcx.generics_of(impl_def_id);
|
||||||
|
let impl_predicates = tcx.predicates_of(impl_def_id);
|
||||||
|
let impl_trait_ref = tcx.impl_trait_ref(impl_def_id).map(ty::EarlyBinder::instantiate_identity);
|
||||||
|
|
||||||
|
impl_trait_ref.error_reported()?;
|
||||||
|
|
||||||
|
let mut input_parameters = cgp::parameters_for_impl(tcx, impl_self_ty, impl_trait_ref);
|
||||||
|
cgp::identify_constrained_generic_params(
|
||||||
|
tcx,
|
||||||
|
impl_predicates,
|
||||||
|
impl_trait_ref,
|
||||||
|
&mut input_parameters,
|
||||||
|
);
|
||||||
|
|
||||||
|
let mut res = Ok(());
|
||||||
|
for param in &impl_generics.own_params {
|
||||||
|
let err = match param.kind {
|
||||||
|
// Disallow ANY unconstrained type parameters.
|
||||||
|
ty::GenericParamDefKind::Type { .. } => {
|
||||||
|
let param_ty = ty::ParamTy::for_def(param);
|
||||||
|
!input_parameters.contains(&cgp::Parameter::from(param_ty))
|
||||||
|
}
|
||||||
|
ty::GenericParamDefKind::Const { .. } => {
|
||||||
|
let param_ct = ty::ParamConst::for_def(param);
|
||||||
|
!input_parameters.contains(&cgp::Parameter::from(param_ct))
|
||||||
|
}
|
||||||
|
ty::GenericParamDefKind::Lifetime => {
|
||||||
|
// Enforced in `enforce_impl_type_params_are_constrained`.
|
||||||
|
false
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if err {
|
||||||
|
let const_param_note = matches!(param.kind, ty::GenericParamDefKind::Const { .. });
|
||||||
|
let mut diag = tcx.dcx().create_err(UnconstrainedGenericParameter {
|
||||||
|
span: tcx.def_span(param.def_id),
|
||||||
|
param_name: param.name,
|
||||||
|
param_def_kind: tcx.def_descr(param.def_id),
|
||||||
|
const_param_note,
|
||||||
|
const_param_note2: const_param_note,
|
||||||
|
});
|
||||||
|
diag.code(E0207);
|
||||||
|
res = Err(diag.emit());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
res
|
||||||
|
}
|
||||||
|
|
|
@ -128,6 +128,8 @@ pub fn provide(providers: &mut Providers) {
|
||||||
hir_wf_check::provide(providers);
|
hir_wf_check::provide(providers);
|
||||||
*providers = Providers {
|
*providers = Providers {
|
||||||
inherit_sig_for_delegation_item: delegation::inherit_sig_for_delegation_item,
|
inherit_sig_for_delegation_item: delegation::inherit_sig_for_delegation_item,
|
||||||
|
enforce_impl_non_lifetime_params_are_constrained:
|
||||||
|
impl_wf_check::enforce_impl_non_lifetime_params_are_constrained,
|
||||||
..*providers
|
..*providers
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -1716,6 +1716,11 @@ rustc_queries! {
|
||||||
ensure_forwards_result_if_red
|
ensure_forwards_result_if_red
|
||||||
}
|
}
|
||||||
|
|
||||||
|
query enforce_impl_non_lifetime_params_are_constrained(key: LocalDefId) -> Result<(), ErrorGuaranteed> {
|
||||||
|
desc { |tcx| "checking that `{}`'s generics are constrained by the impl header", tcx.def_path_str(key) }
|
||||||
|
ensure_forwards_result_if_red
|
||||||
|
}
|
||||||
|
|
||||||
// The `DefId`s of all non-generic functions and statics in the given crate
|
// The `DefId`s of all non-generic functions and statics in the given crate
|
||||||
// that can be reached from outside the crate.
|
// that can be reached from outside the crate.
|
||||||
//
|
//
|
||||||
|
|
|
@ -95,7 +95,10 @@ pub trait SolverDelegate: Deref<Target = <Self as SolverDelegate>::Infcx> + Size
|
||||||
goal_trait_ref: ty::TraitRef<Self::Interner>,
|
goal_trait_ref: ty::TraitRef<Self::Interner>,
|
||||||
trait_assoc_def_id: <Self::Interner as Interner>::DefId,
|
trait_assoc_def_id: <Self::Interner as Interner>::DefId,
|
||||||
impl_def_id: <Self::Interner as Interner>::DefId,
|
impl_def_id: <Self::Interner as Interner>::DefId,
|
||||||
) -> Result<Option<<Self::Interner as Interner>::DefId>, NoSolution>;
|
) -> Result<
|
||||||
|
Option<<Self::Interner as Interner>::DefId>,
|
||||||
|
<Self::Interner as Interner>::ErrorGuaranteed,
|
||||||
|
>;
|
||||||
|
|
||||||
fn is_transmutable(
|
fn is_transmutable(
|
||||||
&self,
|
&self,
|
||||||
|
|
|
@ -950,7 +950,7 @@ where
|
||||||
goal_trait_ref: ty::TraitRef<I>,
|
goal_trait_ref: ty::TraitRef<I>,
|
||||||
trait_assoc_def_id: I::DefId,
|
trait_assoc_def_id: I::DefId,
|
||||||
impl_def_id: I::DefId,
|
impl_def_id: I::DefId,
|
||||||
) -> Result<Option<I::DefId>, NoSolution> {
|
) -> Result<Option<I::DefId>, I::ErrorGuaranteed> {
|
||||||
self.delegate.fetch_eligible_assoc_item(goal_trait_ref, trait_assoc_def_id, impl_def_id)
|
self.delegate.fetch_eligible_assoc_item(goal_trait_ref, trait_assoc_def_id, impl_def_id)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -244,20 +244,7 @@ where
|
||||||
.map(|pred| goal.with(cx, pred)),
|
.map(|pred| goal.with(cx, pred)),
|
||||||
);
|
);
|
||||||
|
|
||||||
// In case the associated item is hidden due to specialization, we have to
|
let error_response = |ecx: &mut EvalCtxt<'_, D>, guar| {
|
||||||
// return ambiguity this would otherwise be incomplete, resulting in
|
|
||||||
// unsoundness during coherence (#105782).
|
|
||||||
let Some(target_item_def_id) = ecx.fetch_eligible_assoc_item(
|
|
||||||
goal_trait_ref,
|
|
||||||
goal.predicate.def_id(),
|
|
||||||
impl_def_id,
|
|
||||||
)?
|
|
||||||
else {
|
|
||||||
return ecx.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS);
|
|
||||||
};
|
|
||||||
|
|
||||||
let error_response = |ecx: &mut EvalCtxt<'_, D>, msg: &str| {
|
|
||||||
let guar = cx.delay_bug(msg);
|
|
||||||
let error_term = match goal.predicate.alias.kind(cx) {
|
let error_term = match goal.predicate.alias.kind(cx) {
|
||||||
ty::AliasTermKind::ProjectionTy => Ty::new_error(cx, guar).into(),
|
ty::AliasTermKind::ProjectionTy => Ty::new_error(cx, guar).into(),
|
||||||
ty::AliasTermKind::ProjectionConst => Const::new_error(cx, guar).into(),
|
ty::AliasTermKind::ProjectionConst => Const::new_error(cx, guar).into(),
|
||||||
|
@ -267,8 +254,24 @@ where
|
||||||
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
|
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// In case the associated item is hidden due to specialization, we have to
|
||||||
|
// return ambiguity this would otherwise be incomplete, resulting in
|
||||||
|
// unsoundness during coherence (#105782).
|
||||||
|
let target_item_def_id = match ecx.fetch_eligible_assoc_item(
|
||||||
|
goal_trait_ref,
|
||||||
|
goal.predicate.def_id(),
|
||||||
|
impl_def_id,
|
||||||
|
) {
|
||||||
|
Ok(Some(target_item_def_id)) => target_item_def_id,
|
||||||
|
Ok(None) => {
|
||||||
|
return ecx
|
||||||
|
.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS);
|
||||||
|
}
|
||||||
|
Err(guar) => return error_response(ecx, guar),
|
||||||
|
};
|
||||||
|
|
||||||
if !cx.has_item_definition(target_item_def_id) {
|
if !cx.has_item_definition(target_item_def_id) {
|
||||||
return error_response(ecx, "missing item");
|
return error_response(ecx, cx.delay_bug("missing item"));
|
||||||
}
|
}
|
||||||
|
|
||||||
let target_container_def_id = cx.parent(target_item_def_id);
|
let target_container_def_id = cx.parent(target_item_def_id);
|
||||||
|
@ -292,7 +295,10 @@ where
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
if !cx.check_args_compatible(target_item_def_id, target_args) {
|
if !cx.check_args_compatible(target_item_def_id, target_args) {
|
||||||
return error_response(ecx, "associated item has mismatched arguments");
|
return error_response(
|
||||||
|
ecx,
|
||||||
|
cx.delay_bug("associated item has mismatched arguments"),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Finally we construct the actual value of the associated type.
|
// Finally we construct the actual value of the associated type.
|
||||||
|
|
|
@ -190,9 +190,8 @@ impl<'tcx> rustc_next_trait_solver::delegate::SolverDelegate for SolverDelegate<
|
||||||
goal_trait_ref: ty::TraitRef<'tcx>,
|
goal_trait_ref: ty::TraitRef<'tcx>,
|
||||||
trait_assoc_def_id: DefId,
|
trait_assoc_def_id: DefId,
|
||||||
impl_def_id: DefId,
|
impl_def_id: DefId,
|
||||||
) -> Result<Option<DefId>, NoSolution> {
|
) -> Result<Option<DefId>, ErrorGuaranteed> {
|
||||||
let node_item = specialization_graph::assoc_def(self.tcx, impl_def_id, trait_assoc_def_id)
|
let node_item = specialization_graph::assoc_def(self.tcx, impl_def_id, trait_assoc_def_id)?;
|
||||||
.map_err(|ErrorGuaranteed { .. }| NoSolution)?;
|
|
||||||
|
|
||||||
let eligible = if node_item.is_final() {
|
let eligible = if node_item.is_final() {
|
||||||
// Non-specializable items are always projectable.
|
// Non-specializable items are always projectable.
|
||||||
|
|
|
@ -950,13 +950,12 @@ fn assemble_candidates_from_impls<'cx, 'tcx>(
|
||||||
//
|
//
|
||||||
// NOTE: This should be kept in sync with the similar code in
|
// NOTE: This should be kept in sync with the similar code in
|
||||||
// `rustc_ty_utils::instance::resolve_associated_item()`.
|
// `rustc_ty_utils::instance::resolve_associated_item()`.
|
||||||
let node_item = specialization_graph::assoc_def(
|
match specialization_graph::assoc_def(
|
||||||
selcx.tcx(),
|
selcx.tcx(),
|
||||||
impl_data.impl_def_id,
|
impl_data.impl_def_id,
|
||||||
obligation.predicate.def_id,
|
obligation.predicate.def_id,
|
||||||
)
|
) {
|
||||||
.map_err(|ErrorGuaranteed { .. }| ())?;
|
Ok(node_item) => {
|
||||||
|
|
||||||
if node_item.is_final() {
|
if node_item.is_final() {
|
||||||
// Non-specializable items are always projectable.
|
// Non-specializable items are always projectable.
|
||||||
true
|
true
|
||||||
|
@ -972,19 +971,26 @@ fn assemble_candidates_from_impls<'cx, 'tcx>(
|
||||||
debug!(
|
debug!(
|
||||||
assoc_ty = ?selcx.tcx().def_path_str(node_item.item.def_id),
|
assoc_ty = ?selcx.tcx().def_path_str(node_item.item.def_id),
|
||||||
?obligation.predicate,
|
?obligation.predicate,
|
||||||
"assemble_candidates_from_impls: not eligible due to default",
|
"not eligible due to default",
|
||||||
);
|
);
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
TypingMode::PostAnalysis => {
|
TypingMode::PostAnalysis => {
|
||||||
// NOTE(eddyb) inference variables can resolve to parameters, so
|
// NOTE(eddyb) inference variables can resolve to parameters, so
|
||||||
// assume `poly_trait_ref` isn't monomorphic, if it contains any.
|
// assume `poly_trait_ref` isn't monomorphic, if it contains any.
|
||||||
let poly_trait_ref = selcx.infcx.resolve_vars_if_possible(trait_ref);
|
let poly_trait_ref =
|
||||||
|
selcx.infcx.resolve_vars_if_possible(trait_ref);
|
||||||
!poly_trait_ref.still_further_specializable()
|
!poly_trait_ref.still_further_specializable()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Always project `ErrorGuaranteed`, since this will just help
|
||||||
|
// us propagate `TyKind::Error` around which suppresses ICEs
|
||||||
|
// and spurious, unrelated inference errors.
|
||||||
|
Err(ErrorGuaranteed { .. }) => true,
|
||||||
|
}
|
||||||
|
}
|
||||||
ImplSource::Builtin(BuiltinImplSource::Misc, _) => {
|
ImplSource::Builtin(BuiltinImplSource::Misc, _) => {
|
||||||
// While a builtin impl may be known to exist, the associated type may not yet
|
// While a builtin impl may be known to exist, the associated type may not yet
|
||||||
// be known. Any type with multiple potential associated types is therefore
|
// be known. Any type with multiple potential associated types is therefore
|
||||||
|
@ -2014,7 +2020,6 @@ fn confirm_impl_candidate<'cx, 'tcx>(
|
||||||
Ok(assoc_ty) => assoc_ty,
|
Ok(assoc_ty) => assoc_ty,
|
||||||
Err(guar) => return Progress::error(tcx, guar),
|
Err(guar) => return Progress::error(tcx, guar),
|
||||||
};
|
};
|
||||||
|
|
||||||
if !assoc_ty.item.defaultness(tcx).has_value() {
|
if !assoc_ty.item.defaultness(tcx).has_value() {
|
||||||
// This means that the impl is missing a definition for the
|
// This means that the impl is missing a definition for the
|
||||||
// associated type. This error will be reported by the type
|
// associated type. This error will be reported by the type
|
||||||
|
|
|
@ -376,6 +376,12 @@ pub(crate) fn assoc_def(
|
||||||
// If there is no such item in that impl, this function will fail with a
|
// If there is no such item in that impl, this function will fail with a
|
||||||
// cycle error if the specialization graph is currently being built.
|
// cycle error if the specialization graph is currently being built.
|
||||||
if let Some(&impl_item_id) = tcx.impl_item_implementor_ids(impl_def_id).get(&assoc_def_id) {
|
if let Some(&impl_item_id) = tcx.impl_item_implementor_ids(impl_def_id).get(&assoc_def_id) {
|
||||||
|
// Ensure that the impl is constrained, otherwise projection may give us
|
||||||
|
// bad unconstrained infer vars.
|
||||||
|
if let Some(impl_def_id) = impl_def_id.as_local() {
|
||||||
|
tcx.ensure().enforce_impl_non_lifetime_params_are_constrained(impl_def_id)?;
|
||||||
|
}
|
||||||
|
|
||||||
let item = tcx.associated_item(impl_item_id);
|
let item = tcx.associated_item(impl_item_id);
|
||||||
let impl_node = Node::Impl(impl_def_id);
|
let impl_node = Node::Impl(impl_def_id);
|
||||||
return Ok(LeafDef {
|
return Ok(LeafDef {
|
||||||
|
@ -391,6 +397,14 @@ pub(crate) fn assoc_def(
|
||||||
|
|
||||||
let ancestors = trait_def.ancestors(tcx, impl_def_id)?;
|
let ancestors = trait_def.ancestors(tcx, impl_def_id)?;
|
||||||
if let Some(assoc_item) = ancestors.leaf_def(tcx, assoc_def_id) {
|
if let Some(assoc_item) = ancestors.leaf_def(tcx, assoc_def_id) {
|
||||||
|
// Ensure that the impl is constrained, otherwise projection may give us
|
||||||
|
// bad unconstrained infer vars.
|
||||||
|
if assoc_item.item.container == ty::AssocItemContainer::Impl
|
||||||
|
&& let Some(impl_def_id) = assoc_item.item.container_id(tcx).as_local()
|
||||||
|
{
|
||||||
|
tcx.ensure().enforce_impl_non_lifetime_params_are_constrained(impl_def_id)?;
|
||||||
|
}
|
||||||
|
|
||||||
Ok(assoc_item)
|
Ok(assoc_item)
|
||||||
} else {
|
} else {
|
||||||
// This is saying that neither the trait nor
|
// This is saying that neither the trait nor
|
||||||
|
|
|
@ -1,23 +0,0 @@
|
||||||
//@ known-bug: #123141
|
|
||||||
|
|
||||||
trait Trait {
|
|
||||||
fn next(self) -> Self::Item;
|
|
||||||
type Item;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct Foo<T: ?Sized>(T);
|
|
||||||
|
|
||||||
impl<T: ?Sized, U> Trait for Foo<U> {
|
|
||||||
type Item = Foo<T>;
|
|
||||||
fn next(self) -> Self::Item {
|
|
||||||
loop {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn opaque() -> impl Trait {
|
|
||||||
Foo::<_>(10_u32)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn main() {
|
|
||||||
opaque().next();
|
|
||||||
}
|
|
|
@ -1,22 +0,0 @@
|
||||||
//@ known-bug: rust-lang/rust#125874
|
|
||||||
pub trait A {}
|
|
||||||
|
|
||||||
pub trait Mirror {
|
|
||||||
type Assoc: ?Sized;
|
|
||||||
}
|
|
||||||
impl<T: ?Sized> Mirror for dyn A {
|
|
||||||
type Assoc = T;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct Bar {
|
|
||||||
foo: <dyn A + 'static as Mirror>::Assoc,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn main() {
|
|
||||||
let strct = Bar { foo: 3 };
|
|
||||||
|
|
||||||
match strct {
|
|
||||||
Bar { foo: 1, .. } => {}
|
|
||||||
_ => (),
|
|
||||||
};
|
|
||||||
}
|
|
|
@ -1,11 +0,0 @@
|
||||||
//@ known-bug: rust-lang/rust#126942
|
|
||||||
struct Thing;
|
|
||||||
|
|
||||||
pub trait Every {
|
|
||||||
type Assoc;
|
|
||||||
}
|
|
||||||
impl<T: ?Sized> Every for Thing {
|
|
||||||
type Assoc = T;
|
|
||||||
}
|
|
||||||
|
|
||||||
static I: <Thing as Every>::Assoc = 3;
|
|
|
@ -1,12 +0,0 @@
|
||||||
//@ known-bug: #127804
|
|
||||||
|
|
||||||
struct Thing;
|
|
||||||
|
|
||||||
pub trait Every {
|
|
||||||
type Assoc;
|
|
||||||
}
|
|
||||||
impl<T: ?Sized> Every for Thing {
|
|
||||||
type Assoc = T;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn foo(_: <Thing as Every>::Assoc) {}
|
|
|
@ -1,13 +0,0 @@
|
||||||
//@ known-bug: #130967
|
|
||||||
|
|
||||||
trait Producer {
|
|
||||||
type Produced;
|
|
||||||
fn make_one() -> Self::Produced;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<E: ?Sized> Producer for () {
|
|
||||||
type Produced = Option<E>;
|
|
||||||
fn make_one() -> Self::Produced {
|
|
||||||
loop {}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -22,73 +22,7 @@ help: consider adding an explicit lifetime bound
|
||||||
LL | type Output<'a> = FooRef<'a, U> where Self: 'a, U: 'a;
|
LL | type Output<'a> = FooRef<'a, U> where Self: 'a, U: 'a;
|
||||||
| +++++++
|
| +++++++
|
||||||
|
|
||||||
error[E0309]: the parameter type `T` may not live long enough
|
error: aborting due to 2 previous errors
|
||||||
--> $DIR/issue-87735.rs:31:15
|
|
||||||
|
|
|
||||||
LL | impl<'b, T, U> AsRef2 for Foo<T>
|
|
||||||
| -- the parameter type `T` must be valid for the lifetime `'b` as defined here...
|
|
||||||
...
|
|
||||||
LL | T: AsRef2<Output<'b> = &'b [U]>,
|
|
||||||
| ^^^^^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds...
|
|
||||||
|
|
|
||||||
note: ...that is required by this bound
|
|
||||||
--> $DIR/issue-87735.rs:7:31
|
|
||||||
|
|
|
||||||
LL | type Output<'a> where Self: 'a;
|
|
||||||
| ^^
|
|
||||||
help: consider adding an explicit lifetime bound
|
|
||||||
|
|
|
||||||
LL | T: AsRef2<Output<'b> = &'b [U]> + 'b,
|
|
||||||
| ++++
|
|
||||||
|
|
||||||
error[E0309]: the parameter type `T` may not live long enough
|
|
||||||
--> $DIR/issue-87735.rs:36:31
|
|
||||||
|
|
|
||||||
LL | impl<'b, T, U> AsRef2 for Foo<T>
|
|
||||||
| -- the parameter type `T` must be valid for the lifetime `'b` as defined here...
|
|
||||||
...
|
|
||||||
LL | fn as_ref2<'a>(&'a self) -> Self::Output<'a> {
|
|
||||||
| ^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds...
|
|
||||||
|
|
|
||||||
note: ...that is required by this bound
|
|
||||||
--> $DIR/issue-87735.rs:7:31
|
|
||||||
|
|
|
||||||
LL | type Output<'a> where Self: 'a;
|
|
||||||
| ^^
|
|
||||||
help: consider adding an explicit lifetime bound
|
|
||||||
|
|
|
||||||
LL | T: AsRef2<Output<'b> = &'b [U]> + 'b,
|
|
||||||
| ++++
|
|
||||||
|
|
||||||
error: lifetime may not live long enough
|
|
||||||
--> $DIR/issue-87735.rs:37:5
|
|
||||||
|
|
|
||||||
LL | impl<'b, T, U> AsRef2 for Foo<T>
|
|
||||||
| -- lifetime `'b` defined here
|
|
||||||
...
|
|
||||||
LL | fn as_ref2<'a>(&'a self) -> Self::Output<'a> {
|
|
||||||
| -- lifetime `'a` defined here
|
|
||||||
LL | FooRef(self.0.as_ref2())
|
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^ method was supposed to return data with lifetime `'a` but it is returning data with lifetime `'b`
|
|
||||||
|
|
|
||||||
= help: consider adding the following bound: `'b: 'a`
|
|
||||||
|
|
||||||
error: lifetime may not live long enough
|
|
||||||
--> $DIR/issue-87735.rs:37:12
|
|
||||||
|
|
|
||||||
LL | impl<'b, T, U> AsRef2 for Foo<T>
|
|
||||||
| -- lifetime `'b` defined here
|
|
||||||
...
|
|
||||||
LL | fn as_ref2<'a>(&'a self) -> Self::Output<'a> {
|
|
||||||
| -- lifetime `'a` defined here
|
|
||||||
LL | FooRef(self.0.as_ref2())
|
|
||||||
| ^^^^^^^^^^^^^^^^ argument requires that `'a` must outlive `'b`
|
|
||||||
|
|
|
||||||
= help: consider adding the following bound: `'a: 'b`
|
|
||||||
|
|
||||||
help: `'b` and `'a` must be the same: replace one with the other
|
|
||||||
|
|
||||||
error: aborting due to 6 previous errors
|
|
||||||
|
|
||||||
Some errors have detailed explanations: E0207, E0309.
|
Some errors have detailed explanations: E0207, E0309.
|
||||||
For more information about an error, try `rustc --explain E0207`.
|
For more information about an error, try `rustc --explain E0207`.
|
||||||
|
|
|
@ -13,7 +13,6 @@ impl<T: ?Sized> Mirror for () {
|
||||||
|
|
||||||
pub trait First {
|
pub trait First {
|
||||||
async fn first() -> <() as Mirror>::Assoc;
|
async fn first() -> <() as Mirror>::Assoc;
|
||||||
//~^ ERROR type annotations needed
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl First for () {
|
impl First for () {
|
||||||
|
|
|
@ -4,13 +4,6 @@ error[E0207]: the type parameter `T` is not constrained by the impl trait, self
|
||||||
LL | impl<T: ?Sized> Mirror for () {
|
LL | impl<T: ?Sized> Mirror for () {
|
||||||
| ^ unconstrained type parameter
|
| ^ unconstrained type parameter
|
||||||
|
|
||||||
error[E0282]: type annotations needed
|
error: aborting due to 1 previous error
|
||||||
--> $DIR/refine-resolution-errors.rs:15:5
|
|
||||||
|
|
|
||||||
LL | async fn first() -> <() as Mirror>::Assoc;
|
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type
|
|
||||||
|
|
||||||
error: aborting due to 2 previous errors
|
For more information about this error, try `rustc --explain E0207`.
|
||||||
|
|
||||||
Some errors have detailed explanations: E0207, E0282.
|
|
||||||
For more information about an error, try `rustc --explain E0207`.
|
|
||||||
|
|
|
@ -9,8 +9,6 @@ impl<T> X for () {
|
||||||
//~^ ERROR `T` is not constrained by the impl trait, self type, or predicates
|
//~^ ERROR `T` is not constrained by the impl trait, self type, or predicates
|
||||||
type I = impl Sized;
|
type I = impl Sized;
|
||||||
fn f() -> Self::I {}
|
fn f() -> Self::I {}
|
||||||
//~^ ERROR type annotations needed
|
|
||||||
//~| ERROR type annotations needed
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {}
|
fn main() {}
|
||||||
|
|
|
@ -4,19 +4,6 @@ error[E0207]: the type parameter `T` is not constrained by the impl trait, self
|
||||||
LL | impl<T> X for () {
|
LL | impl<T> X for () {
|
||||||
| ^ unconstrained type parameter
|
| ^ unconstrained type parameter
|
||||||
|
|
||||||
error[E0282]: type annotations needed
|
error: aborting due to 1 previous error
|
||||||
--> $DIR/issue-87340.rs:11:23
|
|
||||||
|
|
|
||||||
LL | fn f() -> Self::I {}
|
|
||||||
| ^^ cannot infer type for type parameter `T`
|
|
||||||
|
|
||||||
error[E0282]: type annotations needed
|
For more information about this error, try `rustc --explain E0207`.
|
||||||
--> $DIR/issue-87340.rs:11:15
|
|
||||||
|
|
|
||||||
LL | fn f() -> Self::I {}
|
|
||||||
| ^^^^^^^ cannot infer type for type parameter `T`
|
|
||||||
|
|
||||||
error: aborting due to 3 previous errors
|
|
||||||
|
|
||||||
Some errors have detailed explanations: E0207, E0282.
|
|
||||||
For more information about an error, try `rustc --explain E0207`.
|
|
||||||
|
|
|
@ -7,6 +7,12 @@ LL | impl<T> Foo<T> for [isize; 0] {
|
||||||
LL | impl<T, U> Foo<T> for U {
|
LL | impl<T, U> Foo<T> for U {
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `[isize; 0]`
|
| ^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `[isize; 0]`
|
||||||
|
|
||||||
|
error[E0207]: the type parameter `U` is not constrained by the impl trait, self type, or predicates
|
||||||
|
--> $DIR/impl-unused-tps.rs:32:9
|
||||||
|
|
|
||||||
|
LL | impl<T, U> Bar for T {
|
||||||
|
| ^ unconstrained type parameter
|
||||||
|
|
||||||
error[E0119]: conflicting implementations of trait `Bar`
|
error[E0119]: conflicting implementations of trait `Bar`
|
||||||
--> $DIR/impl-unused-tps.rs:40:1
|
--> $DIR/impl-unused-tps.rs:40:1
|
||||||
|
|
|
|
||||||
|
@ -46,12 +52,6 @@ error[E0207]: the type parameter `U` is not constrained by the impl trait, self
|
||||||
LL | impl<T, U> Foo<T> for [isize; 1] {
|
LL | impl<T, U> Foo<T> for [isize; 1] {
|
||||||
| ^ unconstrained type parameter
|
| ^ unconstrained type parameter
|
||||||
|
|
||||||
error[E0207]: the type parameter `U` is not constrained by the impl trait, self type, or predicates
|
|
||||||
--> $DIR/impl-unused-tps.rs:32:9
|
|
||||||
|
|
|
||||||
LL | impl<T, U> Bar for T {
|
|
||||||
| ^ unconstrained type parameter
|
|
||||||
|
|
||||||
error[E0207]: the type parameter `U` is not constrained by the impl trait, self type, or predicates
|
error[E0207]: the type parameter `U` is not constrained by the impl trait, self type, or predicates
|
||||||
--> $DIR/impl-unused-tps.rs:40:9
|
--> $DIR/impl-unused-tps.rs:40:9
|
||||||
|
|
|
|
||||||
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
error[E0207]: the type parameter `T` is not constrained by the impl trait, self type, or predicates
|
||||||
|
--> $DIR/unconstrained-projection-normalization-2.rs:14:6
|
||||||
|
|
|
||||||
|
LL | impl<T: ?Sized> Every for Thing {
|
||||||
|
| ^ unconstrained type parameter
|
||||||
|
|
||||||
|
error: aborting due to 1 previous error
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0207`.
|
|
@ -0,0 +1,9 @@
|
||||||
|
error[E0207]: the type parameter `T` is not constrained by the impl trait, self type, or predicates
|
||||||
|
--> $DIR/unconstrained-projection-normalization-2.rs:14:6
|
||||||
|
|
|
||||||
|
LL | impl<T: ?Sized> Every for Thing {
|
||||||
|
| ^ unconstrained type parameter
|
||||||
|
|
||||||
|
error: aborting due to 1 previous error
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0207`.
|
21
tests/ui/traits/unconstrained-projection-normalization-2.rs
Normal file
21
tests/ui/traits/unconstrained-projection-normalization-2.rs
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
// Make sure we don't ICE in `normalize_erasing_regions` when normalizing
|
||||||
|
// an associated type in an impl with unconstrained non-lifetime params.
|
||||||
|
// (This time in a function signature)
|
||||||
|
|
||||||
|
//@ revisions: current next
|
||||||
|
//@ ignore-compare-mode-next-solver (explicit revisions)
|
||||||
|
//@[next] compile-flags: -Znext-solver
|
||||||
|
|
||||||
|
struct Thing;
|
||||||
|
|
||||||
|
pub trait Every {
|
||||||
|
type Assoc;
|
||||||
|
}
|
||||||
|
impl<T: ?Sized> Every for Thing {
|
||||||
|
//~^ ERROR the type parameter `T` is not constrained
|
||||||
|
type Assoc = T;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn foo(_: <Thing as Every>::Assoc) {}
|
||||||
|
|
||||||
|
fn main() {}
|
|
@ -0,0 +1,9 @@
|
||||||
|
error[E0207]: the type parameter `T` is not constrained by the impl trait, self type, or predicates
|
||||||
|
--> $DIR/unconstrained-projection-normalization.rs:13:6
|
||||||
|
|
|
||||||
|
LL | impl<T: ?Sized> Every for Thing {
|
||||||
|
| ^ unconstrained type parameter
|
||||||
|
|
||||||
|
error: aborting due to 1 previous error
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0207`.
|
|
@ -0,0 +1,9 @@
|
||||||
|
error[E0207]: the type parameter `T` is not constrained by the impl trait, self type, or predicates
|
||||||
|
--> $DIR/unconstrained-projection-normalization.rs:13:6
|
||||||
|
|
|
||||||
|
LL | impl<T: ?Sized> Every for Thing {
|
||||||
|
| ^ unconstrained type parameter
|
||||||
|
|
||||||
|
error: aborting due to 1 previous error
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0207`.
|
20
tests/ui/traits/unconstrained-projection-normalization.rs
Normal file
20
tests/ui/traits/unconstrained-projection-normalization.rs
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
// Make sure we don't ICE in `normalize_erasing_regions` when normalizing
|
||||||
|
// an associated type in an impl with unconstrained non-lifetime params.
|
||||||
|
|
||||||
|
//@ revisions: current next
|
||||||
|
//@ ignore-compare-mode-next-solver (explicit revisions)
|
||||||
|
//@[next] compile-flags: -Znext-solver
|
||||||
|
|
||||||
|
struct Thing;
|
||||||
|
|
||||||
|
pub trait Every {
|
||||||
|
type Assoc;
|
||||||
|
}
|
||||||
|
impl<T: ?Sized> Every for Thing {
|
||||||
|
//~^ ERROR the type parameter `T` is not constrained
|
||||||
|
type Assoc = T;
|
||||||
|
}
|
||||||
|
|
||||||
|
static I: <Thing as Every>::Assoc = 3;
|
||||||
|
|
||||||
|
fn main() {}
|
|
@ -42,7 +42,6 @@ impl<T: MyFrom<Phantom2<DummyT<U>>>, U> MyIndex<DummyT<T>> for Scope<U> {
|
||||||
//~^ ERROR the type parameter `T` is not constrained by the impl
|
//~^ ERROR the type parameter `T` is not constrained by the impl
|
||||||
type O = T;
|
type O = T;
|
||||||
fn my_index(self) -> Self::O {
|
fn my_index(self) -> Self::O {
|
||||||
//~^ ERROR item does not constrain
|
|
||||||
MyFrom::my_from(self.0).ok().unwrap()
|
MyFrom::my_from(self.0).ok().unwrap()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,19 +17,6 @@ note: this opaque type is in the signature
|
||||||
LL | type DummyT<T> = impl F;
|
LL | type DummyT<T> = impl F;
|
||||||
| ^^^^^^
|
| ^^^^^^
|
||||||
|
|
||||||
error: item does not constrain `DummyT::{opaque#0}`, but has it in its signature
|
error: aborting due to 2 previous errors
|
||||||
--> $DIR/ice-failed-to-resolve-instance-for-110696.rs:44:8
|
|
||||||
|
|
|
||||||
LL | fn my_index(self) -> Self::O {
|
|
||||||
| ^^^^^^^^
|
|
||||||
|
|
|
||||||
= note: consider moving the opaque type's declaration and defining uses into a separate module
|
|
||||||
note: this opaque type is in the signature
|
|
||||||
--> $DIR/ice-failed-to-resolve-instance-for-110696.rs:20:18
|
|
||||||
|
|
|
||||||
LL | type DummyT<T> = impl F;
|
|
||||||
| ^^^^^^
|
|
||||||
|
|
||||||
error: aborting due to 3 previous errors
|
|
||||||
|
|
||||||
For more information about this error, try `rustc --explain E0207`.
|
For more information about this error, try `rustc --explain E0207`.
|
||||||
|
|
|
@ -12,8 +12,6 @@ impl<T> X for () {
|
||||||
//~^ ERROR the type parameter `T` is not constrained
|
//~^ ERROR the type parameter `T` is not constrained
|
||||||
type I = impl Sized;
|
type I = impl Sized;
|
||||||
fn f() -> Self::I {}
|
fn f() -> Self::I {}
|
||||||
//~^ ERROR type annotations needed
|
|
||||||
//~| ERROR type annotations needed
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {}
|
fn main() {}
|
||||||
|
|
|
@ -4,19 +4,6 @@ error[E0207]: the type parameter `T` is not constrained by the impl trait, self
|
||||||
LL | impl<T> X for () {
|
LL | impl<T> X for () {
|
||||||
| ^ unconstrained type parameter
|
| ^ unconstrained type parameter
|
||||||
|
|
||||||
error[E0282]: type annotations needed
|
error: aborting due to 1 previous error
|
||||||
--> $DIR/impl-with-unconstrained-param.rs:14:23
|
|
||||||
|
|
|
||||||
LL | fn f() -> Self::I {}
|
|
||||||
| ^^ cannot infer type for type parameter `T`
|
|
||||||
|
|
||||||
error[E0282]: type annotations needed
|
For more information about this error, try `rustc --explain E0207`.
|
||||||
--> $DIR/impl-with-unconstrained-param.rs:14:15
|
|
||||||
|
|
|
||||||
LL | fn f() -> Self::I {}
|
|
||||||
| ^^^^^^^ cannot infer type for type parameter `T`
|
|
||||||
|
|
||||||
error: aborting due to 3 previous errors
|
|
||||||
|
|
||||||
Some errors have detailed explanations: E0207, E0282.
|
|
||||||
For more information about an error, try `rustc --explain E0207`.
|
|
||||||
|
|
|
@ -14,7 +14,6 @@ impl<T> Allocator for DefaultAllocator {
|
||||||
type A = impl Fn(<DefaultAllocator as Allocator>::Buffer);
|
type A = impl Fn(<DefaultAllocator as Allocator>::Buffer);
|
||||||
|
|
||||||
fn foo() -> A {
|
fn foo() -> A {
|
||||||
//~^ ERROR: type annotations needed
|
|
||||||
|_| ()
|
|_| ()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,13 +4,6 @@ error[E0207]: the type parameter `T` is not constrained by the impl trait, self
|
||||||
LL | impl<T> Allocator for DefaultAllocator {
|
LL | impl<T> Allocator for DefaultAllocator {
|
||||||
| ^ unconstrained type parameter
|
| ^ unconstrained type parameter
|
||||||
|
|
||||||
error[E0282]: type annotations needed
|
error: aborting due to 1 previous error
|
||||||
--> $DIR/issue-74244.rs:16:13
|
|
||||||
|
|
|
||||||
LL | fn foo() -> A {
|
|
||||||
| ^ cannot infer type for type parameter `T`
|
|
||||||
|
|
||||||
error: aborting due to 2 previous errors
|
For more information about this error, try `rustc --explain E0207`.
|
||||||
|
|
||||||
Some errors have detailed explanations: E0207, E0282.
|
|
||||||
For more information about an error, try `rustc --explain E0207`.
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue