Change InferCtxtBuilder from enter to build
This commit is contained in:
parent
91269fa5b8
commit
283abbf0e7
53 changed files with 1966 additions and 2182 deletions
|
@ -31,9 +31,8 @@ pub fn get_body_with_borrowck_facts<'tcx>(
|
||||||
def: ty::WithOptConstParam<LocalDefId>,
|
def: ty::WithOptConstParam<LocalDefId>,
|
||||||
) -> BodyWithBorrowckFacts<'tcx> {
|
) -> BodyWithBorrowckFacts<'tcx> {
|
||||||
let (input_body, promoted) = tcx.mir_promoted(def);
|
let (input_body, promoted) = tcx.mir_promoted(def);
|
||||||
tcx.infer_ctxt().with_opaque_type_inference(DefiningAnchor::Bind(def.did)).enter(|infcx| {
|
let infcx = tcx.infer_ctxt().with_opaque_type_inference(DefiningAnchor::Bind(def.did)).build();
|
||||||
let input_body: &Body<'_> = &input_body.borrow();
|
let input_body: &Body<'_> = &input_body.borrow();
|
||||||
let promoted: &IndexVec<_, _> = &promoted.borrow();
|
let promoted: &IndexVec<_, _> = &promoted.borrow();
|
||||||
*super::do_mir_borrowck(&infcx, input_body, promoted, true).1.unwrap()
|
*super::do_mir_borrowck(&infcx, input_body, promoted, true).1.unwrap()
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -238,20 +238,11 @@ impl<'tcx> TypeOpInfo<'tcx> for PredicateQuery<'tcx> {
|
||||||
placeholder_region: ty::Region<'tcx>,
|
placeholder_region: ty::Region<'tcx>,
|
||||||
error_region: Option<ty::Region<'tcx>>,
|
error_region: Option<ty::Region<'tcx>>,
|
||||||
) -> Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>> {
|
) -> Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>> {
|
||||||
mbcx.infcx.tcx.infer_ctxt().enter_with_canonical(
|
let (ref infcx, key, _) =
|
||||||
cause.span,
|
mbcx.infcx.tcx.infer_ctxt().build_with_canonical(cause.span, &self.canonical_query);
|
||||||
&self.canonical_query,
|
let mut fulfill_cx = <dyn TraitEngine<'_>>::new(infcx.tcx);
|
||||||
|ref infcx, key, _| {
|
type_op_prove_predicate_with_cause(infcx, &mut *fulfill_cx, key, cause);
|
||||||
let mut fulfill_cx = <dyn TraitEngine<'_>>::new(infcx.tcx);
|
try_extract_error_from_fulfill_cx(fulfill_cx, infcx, placeholder_region, error_region)
|
||||||
type_op_prove_predicate_with_cause(infcx, &mut *fulfill_cx, key, cause);
|
|
||||||
try_extract_error_from_fulfill_cx(
|
|
||||||
fulfill_cx,
|
|
||||||
infcx,
|
|
||||||
placeholder_region,
|
|
||||||
error_region,
|
|
||||||
)
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -288,37 +279,24 @@ where
|
||||||
placeholder_region: ty::Region<'tcx>,
|
placeholder_region: ty::Region<'tcx>,
|
||||||
error_region: Option<ty::Region<'tcx>>,
|
error_region: Option<ty::Region<'tcx>>,
|
||||||
) -> Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>> {
|
) -> Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>> {
|
||||||
mbcx.infcx.tcx.infer_ctxt().enter_with_canonical(
|
let (ref infcx, key, _) =
|
||||||
cause.span,
|
mbcx.infcx.tcx.infer_ctxt().build_with_canonical(cause.span, &self.canonical_query);
|
||||||
&self.canonical_query,
|
let mut fulfill_cx = <dyn TraitEngine<'_>>::new(infcx.tcx);
|
||||||
|ref infcx, key, _| {
|
|
||||||
let mut fulfill_cx = <dyn TraitEngine<'_>>::new(infcx.tcx);
|
|
||||||
|
|
||||||
let mut selcx = SelectionContext::new(infcx);
|
let mut selcx = SelectionContext::new(infcx);
|
||||||
|
|
||||||
// FIXME(lqd): Unify and de-duplicate the following with the actual
|
// FIXME(lqd): Unify and de-duplicate the following with the actual
|
||||||
// `rustc_traits::type_op::type_op_normalize` query to allow the span we need in the
|
// `rustc_traits::type_op::type_op_normalize` query to allow the span we need in the
|
||||||
// `ObligationCause`. The normalization results are currently different between
|
// `ObligationCause`. The normalization results are currently different between
|
||||||
// `AtExt::normalize` used in the query and `normalize` called below: the former fails
|
// `AtExt::normalize` used in the query and `normalize` called below: the former fails
|
||||||
// to normalize the `nll/relate_tys/impl-fn-ignore-binder-via-bottom.rs` test. Check
|
// to normalize the `nll/relate_tys/impl-fn-ignore-binder-via-bottom.rs` test. Check
|
||||||
// after #85499 lands to see if its fixes have erased this difference.
|
// after #85499 lands to see if its fixes have erased this difference.
|
||||||
let (param_env, value) = key.into_parts();
|
let (param_env, value) = key.into_parts();
|
||||||
let Normalized { value: _, obligations } = rustc_trait_selection::traits::normalize(
|
let Normalized { value: _, obligations } =
|
||||||
&mut selcx,
|
rustc_trait_selection::traits::normalize(&mut selcx, param_env, cause, value.value);
|
||||||
param_env,
|
fulfill_cx.register_predicate_obligations(infcx, obligations);
|
||||||
cause,
|
|
||||||
value.value,
|
|
||||||
);
|
|
||||||
fulfill_cx.register_predicate_obligations(infcx, obligations);
|
|
||||||
|
|
||||||
try_extract_error_from_fulfill_cx(
|
try_extract_error_from_fulfill_cx(fulfill_cx, infcx, placeholder_region, error_region)
|
||||||
fulfill_cx,
|
|
||||||
infcx,
|
|
||||||
placeholder_region,
|
|
||||||
error_region,
|
|
||||||
)
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -349,21 +327,11 @@ impl<'tcx> TypeOpInfo<'tcx> for AscribeUserTypeQuery<'tcx> {
|
||||||
placeholder_region: ty::Region<'tcx>,
|
placeholder_region: ty::Region<'tcx>,
|
||||||
error_region: Option<ty::Region<'tcx>>,
|
error_region: Option<ty::Region<'tcx>>,
|
||||||
) -> Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>> {
|
) -> Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>> {
|
||||||
mbcx.infcx.tcx.infer_ctxt().enter_with_canonical(
|
let (ref infcx, key, _) =
|
||||||
cause.span,
|
mbcx.infcx.tcx.infer_ctxt().build_with_canonical(cause.span, &self.canonical_query);
|
||||||
&self.canonical_query,
|
let mut fulfill_cx = <dyn TraitEngine<'_>>::new(infcx.tcx);
|
||||||
|ref infcx, key, _| {
|
type_op_ascribe_user_type_with_span(infcx, &mut *fulfill_cx, key, Some(cause.span)).ok()?;
|
||||||
let mut fulfill_cx = <dyn TraitEngine<'_>>::new(infcx.tcx);
|
try_extract_error_from_fulfill_cx(fulfill_cx, infcx, placeholder_region, error_region)
|
||||||
type_op_ascribe_user_type_with_span(infcx, &mut *fulfill_cx, key, Some(cause.span))
|
|
||||||
.ok()?;
|
|
||||||
try_extract_error_from_fulfill_cx(
|
|
||||||
fulfill_cx,
|
|
||||||
infcx,
|
|
||||||
placeholder_region,
|
|
||||||
error_region,
|
|
||||||
)
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -492,11 +492,10 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||||
let Some(default_trait) = tcx.get_diagnostic_item(sym::Default) else {
|
let Some(default_trait) = tcx.get_diagnostic_item(sym::Default) else {
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
tcx.infer_ctxt().enter(|infcx| {
|
tcx.infer_ctxt()
|
||||||
infcx
|
.build()
|
||||||
.type_implements_trait(default_trait, ty, ty::List::empty(), param_env)
|
.type_implements_trait(default_trait, ty, ty::List::empty(), param_env)
|
||||||
.may_apply()
|
.may_apply()
|
||||||
})
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let assign_value = match ty.kind() {
|
let assign_value = match ty.kind() {
|
||||||
|
@ -606,41 +605,40 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||||
.and_then(|def_id| tcx.hir().get_generics(def_id))
|
.and_then(|def_id| tcx.hir().get_generics(def_id))
|
||||||
else { return; };
|
else { return; };
|
||||||
// Try to find predicates on *generic params* that would allow copying `ty`
|
// Try to find predicates on *generic params* that would allow copying `ty`
|
||||||
let predicates: Result<Vec<_>, _> = tcx.infer_ctxt().enter(|infcx| {
|
let infcx = tcx.infer_ctxt().build();
|
||||||
let mut fulfill_cx = <dyn rustc_infer::traits::TraitEngine<'_>>::new(infcx.tcx);
|
let mut fulfill_cx = <dyn rustc_infer::traits::TraitEngine<'_>>::new(infcx.tcx);
|
||||||
|
|
||||||
let copy_did = infcx.tcx.lang_items().copy_trait().unwrap();
|
let copy_did = infcx.tcx.lang_items().copy_trait().unwrap();
|
||||||
let cause = ObligationCause::new(
|
let cause = ObligationCause::new(
|
||||||
span,
|
span,
|
||||||
self.mir_hir_id(),
|
self.mir_hir_id(),
|
||||||
rustc_infer::traits::ObligationCauseCode::MiscObligation,
|
rustc_infer::traits::ObligationCauseCode::MiscObligation,
|
||||||
);
|
);
|
||||||
fulfill_cx.register_bound(
|
fulfill_cx.register_bound(
|
||||||
&infcx,
|
&infcx,
|
||||||
self.param_env,
|
self.param_env,
|
||||||
// Erase any region vids from the type, which may not be resolved
|
// Erase any region vids from the type, which may not be resolved
|
||||||
infcx.tcx.erase_regions(ty),
|
infcx.tcx.erase_regions(ty),
|
||||||
copy_did,
|
copy_did,
|
||||||
cause,
|
cause,
|
||||||
);
|
);
|
||||||
// Select all, including ambiguous predicates
|
// Select all, including ambiguous predicates
|
||||||
let errors = fulfill_cx.select_all_or_error(&infcx);
|
let errors = fulfill_cx.select_all_or_error(&infcx);
|
||||||
|
|
||||||
// Only emit suggestion if all required predicates are on generic
|
// Only emit suggestion if all required predicates are on generic
|
||||||
errors
|
let predicates: Result<Vec<_>, _> = errors
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|err| match err.obligation.predicate.kind().skip_binder() {
|
.map(|err| match err.obligation.predicate.kind().skip_binder() {
|
||||||
PredicateKind::Trait(predicate) => match predicate.self_ty().kind() {
|
PredicateKind::Trait(predicate) => match predicate.self_ty().kind() {
|
||||||
ty::Param(param_ty) => Ok((
|
ty::Param(param_ty) => Ok((
|
||||||
generics.type_param(param_ty, tcx),
|
generics.type_param(param_ty, tcx),
|
||||||
predicate.trait_ref.print_only_trait_path().to_string(),
|
predicate.trait_ref.print_only_trait_path().to_string(),
|
||||||
)),
|
)),
|
||||||
_ => Err(()),
|
|
||||||
},
|
|
||||||
_ => Err(()),
|
_ => Err(()),
|
||||||
})
|
},
|
||||||
.collect()
|
_ => Err(()),
|
||||||
});
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
if let Ok(predicates) = predicates {
|
if let Ok(predicates) = predicates {
|
||||||
suggest_constraining_type_params(
|
suggest_constraining_type_params(
|
||||||
|
|
|
@ -1025,7 +1025,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||||
if let Some((CallDesugaringKind::ForLoopIntoIter, _)) = desugaring {
|
if let Some((CallDesugaringKind::ForLoopIntoIter, _)) = desugaring {
|
||||||
let ty = moved_place.ty(self.body, self.infcx.tcx).ty;
|
let ty = moved_place.ty(self.body, self.infcx.tcx).ty;
|
||||||
let suggest = match self.infcx.tcx.get_diagnostic_item(sym::IntoIterator) {
|
let suggest = match self.infcx.tcx.get_diagnostic_item(sym::IntoIterator) {
|
||||||
Some(def_id) => self.infcx.tcx.infer_ctxt().enter(|infcx| {
|
Some(def_id) => {
|
||||||
|
let infcx = self.infcx.tcx.infer_ctxt().build();
|
||||||
type_known_to_meet_bound_modulo_regions(
|
type_known_to_meet_bound_modulo_regions(
|
||||||
&infcx,
|
&infcx,
|
||||||
self.param_env,
|
self.param_env,
|
||||||
|
@ -1036,7 +1037,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||||
def_id,
|
def_id,
|
||||||
DUMMY_SP,
|
DUMMY_SP,
|
||||||
)
|
)
|
||||||
}),
|
}
|
||||||
_ => false,
|
_ => false,
|
||||||
};
|
};
|
||||||
if suggest {
|
if suggest {
|
||||||
|
|
|
@ -131,14 +131,11 @@ fn mir_borrowck<'tcx>(
|
||||||
debug!("run query mir_borrowck: {}", tcx.def_path_str(def.did.to_def_id()));
|
debug!("run query mir_borrowck: {}", tcx.def_path_str(def.did.to_def_id()));
|
||||||
let hir_owner = tcx.hir().local_def_id_to_hir_id(def.did).owner;
|
let hir_owner = tcx.hir().local_def_id_to_hir_id(def.did).owner;
|
||||||
|
|
||||||
let opt_closure_req = tcx
|
let infcx =
|
||||||
.infer_ctxt()
|
tcx.infer_ctxt().with_opaque_type_inference(DefiningAnchor::Bind(hir_owner.def_id)).build();
|
||||||
.with_opaque_type_inference(DefiningAnchor::Bind(hir_owner.def_id))
|
let input_body: &Body<'_> = &input_body.borrow();
|
||||||
.enter(|infcx| {
|
let promoted: &IndexVec<_, _> = &promoted.borrow();
|
||||||
let input_body: &Body<'_> = &input_body.borrow();
|
let opt_closure_req = do_mir_borrowck(&infcx, input_body, promoted, false).0;
|
||||||
let promoted: &IndexVec<_, _> = &promoted.borrow();
|
|
||||||
do_mir_borrowck(&infcx, input_body, promoted, false).0
|
|
||||||
});
|
|
||||||
debug!("mir_borrowck done");
|
debug!("mir_borrowck done");
|
||||||
|
|
||||||
tcx.arena.alloc(opt_closure_req)
|
tcx.arena.alloc(opt_closure_req)
|
||||||
|
|
|
@ -266,73 +266,69 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> {
|
||||||
|
|
||||||
// Only check this for TAIT. RPIT already supports `src/test/ui/impl-trait/nested-return-type2.rs`
|
// Only check this for TAIT. RPIT already supports `src/test/ui/impl-trait/nested-return-type2.rs`
|
||||||
// on stable and we'd break that.
|
// on stable and we'd break that.
|
||||||
if let OpaqueTyOrigin::TyAlias = origin {
|
let OpaqueTyOrigin::TyAlias = origin else {
|
||||||
// This logic duplicates most of `check_opaque_meets_bounds`.
|
return definition_ty;
|
||||||
// FIXME(oli-obk): Also do region checks here and then consider removing `check_opaque_meets_bounds` entirely.
|
};
|
||||||
let param_env = self.tcx.param_env(def_id);
|
// This logic duplicates most of `check_opaque_meets_bounds`.
|
||||||
let body_id = self.tcx.local_def_id_to_hir_id(def_id);
|
// FIXME(oli-obk): Also do region checks here and then consider removing `check_opaque_meets_bounds` entirely.
|
||||||
// HACK This bubble is required for this tests to pass:
|
let param_env = self.tcx.param_env(def_id);
|
||||||
// type-alias-impl-trait/issue-67844-nested-opaque.rs
|
let body_id = self.tcx.local_def_id_to_hir_id(def_id);
|
||||||
self.tcx.infer_ctxt().with_opaque_type_inference(DefiningAnchor::Bubble).enter(
|
// HACK This bubble is required for this tests to pass:
|
||||||
move |infcx| {
|
// type-alias-impl-trait/issue-67844-nested-opaque.rs
|
||||||
// Require the hidden type to be well-formed with only the generics of the opaque type.
|
let infcx =
|
||||||
// Defining use functions may have more bounds than the opaque type, which is ok, as long as the
|
self.tcx.infer_ctxt().with_opaque_type_inference(DefiningAnchor::Bubble).build();
|
||||||
// hidden type is well formed even without those bounds.
|
// Require the hidden type to be well-formed with only the generics of the opaque type.
|
||||||
let predicate =
|
// Defining use functions may have more bounds than the opaque type, which is ok, as long as the
|
||||||
ty::Binder::dummy(ty::PredicateKind::WellFormed(definition_ty.into()))
|
// hidden type is well formed even without those bounds.
|
||||||
.to_predicate(infcx.tcx);
|
let predicate = ty::Binder::dummy(ty::PredicateKind::WellFormed(definition_ty.into()))
|
||||||
let mut fulfillment_cx = <dyn TraitEngine<'tcx>>::new(infcx.tcx);
|
.to_predicate(infcx.tcx);
|
||||||
|
let mut fulfillment_cx = <dyn TraitEngine<'tcx>>::new(infcx.tcx);
|
||||||
|
|
||||||
// Require that the hidden type actually fulfills all the bounds of the opaque type, even without
|
// Require that the hidden type actually fulfills all the bounds of the opaque type, even without
|
||||||
// the bounds that the function supplies.
|
// the bounds that the function supplies.
|
||||||
match infcx.register_hidden_type(
|
match infcx.register_hidden_type(
|
||||||
OpaqueTypeKey { def_id, substs: id_substs },
|
OpaqueTypeKey { def_id, substs: id_substs },
|
||||||
ObligationCause::misc(instantiated_ty.span, body_id),
|
ObligationCause::misc(instantiated_ty.span, body_id),
|
||||||
param_env,
|
param_env,
|
||||||
|
definition_ty,
|
||||||
|
origin,
|
||||||
|
) {
|
||||||
|
Ok(infer_ok) => {
|
||||||
|
for obligation in infer_ok.obligations {
|
||||||
|
fulfillment_cx.register_predicate_obligation(&infcx, obligation);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(err) => {
|
||||||
|
infcx
|
||||||
|
.err_ctxt()
|
||||||
|
.report_mismatched_types(
|
||||||
|
&ObligationCause::misc(instantiated_ty.span, body_id),
|
||||||
|
self.tcx.mk_opaque(def_id.to_def_id(), id_substs),
|
||||||
definition_ty,
|
definition_ty,
|
||||||
origin,
|
err,
|
||||||
) {
|
)
|
||||||
Ok(infer_ok) => {
|
.emit();
|
||||||
for obligation in infer_ok.obligations {
|
}
|
||||||
fulfillment_cx.register_predicate_obligation(&infcx, obligation);
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
Err(err) => {
|
|
||||||
infcx
|
|
||||||
.err_ctxt()
|
|
||||||
.report_mismatched_types(
|
|
||||||
&ObligationCause::misc(instantiated_ty.span, body_id),
|
|
||||||
self.tcx.mk_opaque(def_id.to_def_id(), id_substs),
|
|
||||||
definition_ty,
|
|
||||||
err,
|
|
||||||
)
|
|
||||||
.emit();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fulfillment_cx.register_predicate_obligation(
|
fulfillment_cx.register_predicate_obligation(
|
||||||
&infcx,
|
&infcx,
|
||||||
Obligation::misc(instantiated_ty.span, body_id, param_env, predicate),
|
Obligation::misc(instantiated_ty.span, body_id, param_env, predicate),
|
||||||
);
|
);
|
||||||
|
|
||||||
// Check that all obligations are satisfied by the implementation's
|
// Check that all obligations are satisfied by the implementation's
|
||||||
// version.
|
// version.
|
||||||
let errors = fulfillment_cx.select_all_or_error(&infcx);
|
let errors = fulfillment_cx.select_all_or_error(&infcx);
|
||||||
|
|
||||||
// This is still required for many(half of the tests in ui/type-alias-impl-trait)
|
// This is still required for many(half of the tests in ui/type-alias-impl-trait)
|
||||||
// tests to pass
|
// tests to pass
|
||||||
let _ = infcx.inner.borrow_mut().opaque_type_storage.take_opaque_types();
|
let _ = infcx.inner.borrow_mut().opaque_type_storage.take_opaque_types();
|
||||||
|
|
||||||
if errors.is_empty() {
|
if errors.is_empty() {
|
||||||
definition_ty
|
|
||||||
} else {
|
|
||||||
infcx.err_ctxt().report_fulfillment_errors(&errors, None, false);
|
|
||||||
self.tcx.ty_error()
|
|
||||||
}
|
|
||||||
},
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
definition_ty
|
definition_ty
|
||||||
|
} else {
|
||||||
|
infcx.err_ctxt().report_fulfillment_errors(&errors, None, false);
|
||||||
|
self.tcx.ty_error()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -737,14 +737,16 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
|
||||||
let obligation =
|
let obligation =
|
||||||
Obligation::new(ObligationCause::dummy(), param_env, poly_trait_pred);
|
Obligation::new(ObligationCause::dummy(), param_env, poly_trait_pred);
|
||||||
|
|
||||||
let implsrc = tcx.infer_ctxt().enter(|infcx| {
|
let implsrc = {
|
||||||
|
let infcx = tcx.infer_ctxt().build();
|
||||||
let mut selcx = SelectionContext::new(&infcx);
|
let mut selcx = SelectionContext::new(&infcx);
|
||||||
selcx.select(&obligation)
|
selcx.select(&obligation)
|
||||||
});
|
};
|
||||||
|
|
||||||
// do a well-formedness check on the trait method being called. This is because typeck only does a
|
// do a well-formedness check on the trait method being called. This is because typeck only does a
|
||||||
// "non-const" check. This is required for correctness here.
|
// "non-const" check. This is required for correctness here.
|
||||||
tcx.infer_ctxt().enter(|infcx| {
|
{
|
||||||
|
let infcx = tcx.infer_ctxt().build();
|
||||||
let mut fulfill_cx = <dyn TraitEngine<'_>>::new(infcx.tcx);
|
let mut fulfill_cx = <dyn TraitEngine<'_>>::new(infcx.tcx);
|
||||||
let predicates = tcx.predicates_of(callee).instantiate(tcx, substs);
|
let predicates = tcx.predicates_of(callee).instantiate(tcx, substs);
|
||||||
let hir_id = tcx
|
let hir_id = tcx
|
||||||
|
@ -777,7 +779,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
|
||||||
if !errors.is_empty() {
|
if !errors.is_empty() {
|
||||||
infcx.err_ctxt().report_fulfillment_errors(&errors, None, false);
|
infcx.err_ctxt().report_fulfillment_errors(&errors, None, false);
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
|
|
||||||
match implsrc {
|
match implsrc {
|
||||||
Ok(Some(ImplSource::Param(_, ty::BoundConstness::ConstIfConst))) => {
|
Ok(Some(ImplSource::Param(_, ty::BoundConstness::ConstIfConst))) => {
|
||||||
|
@ -835,16 +837,15 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
|
||||||
|
|
||||||
// improve diagnostics by showing what failed. Our requirements are stricter this time
|
// improve diagnostics by showing what failed. Our requirements are stricter this time
|
||||||
// as we are going to error again anyways.
|
// as we are going to error again anyways.
|
||||||
tcx.infer_ctxt().enter(|infcx| {
|
let infcx = tcx.infer_ctxt().build();
|
||||||
if let Err(e) = implsrc {
|
if let Err(e) = implsrc {
|
||||||
infcx.err_ctxt().report_selection_error(
|
infcx.err_ctxt().report_selection_error(
|
||||||
obligation.clone(),
|
obligation.clone(),
|
||||||
&obligation,
|
&obligation,
|
||||||
&e,
|
&e,
|
||||||
false,
|
false,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
});
|
|
||||||
|
|
||||||
self.check_op(ops::FnCallNonConst {
|
self.check_op(ops::FnCallNonConst {
|
||||||
caller,
|
caller,
|
||||||
|
|
|
@ -156,10 +156,9 @@ impl<'tcx> NonConstOp<'tcx> for FnCallNonConst<'tcx> {
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
let implsrc = tcx.infer_ctxt().enter(|infcx| {
|
let infcx = tcx.infer_ctxt().build();
|
||||||
let mut selcx = SelectionContext::new(&infcx);
|
let mut selcx = SelectionContext::new(&infcx);
|
||||||
selcx.select(&obligation)
|
let implsrc = selcx.select(&obligation);
|
||||||
});
|
|
||||||
|
|
||||||
if let Ok(Some(ImplSource::UserDefined(data))) = implsrc {
|
if let Ok(Some(ImplSource::UserDefined(data))) = implsrc {
|
||||||
let span = tcx.def_span(data.impl_def_id);
|
let span = tcx.def_span(data.impl_def_id);
|
||||||
|
|
|
@ -168,30 +168,28 @@ impl Qualif for NeedsNonConstDrop {
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
cx.tcx.infer_ctxt().enter(|infcx| {
|
let infcx = cx.tcx.infer_ctxt().build();
|
||||||
let mut selcx = SelectionContext::new(&infcx);
|
let mut selcx = SelectionContext::new(&infcx);
|
||||||
let Some(impl_src) = selcx.select(&obligation).ok().flatten() else {
|
let Some(impl_src) = selcx.select(&obligation).ok().flatten() else {
|
||||||
// If we couldn't select a const destruct candidate, then it's bad
|
// If we couldn't select a const destruct candidate, then it's bad
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
if !matches!(
|
if !matches!(
|
||||||
impl_src,
|
impl_src,
|
||||||
ImplSource::ConstDestruct(_)
|
ImplSource::ConstDestruct(_) | ImplSource::Param(_, ty::BoundConstness::ConstIfConst)
|
||||||
| ImplSource::Param(_, ty::BoundConstness::ConstIfConst)
|
) {
|
||||||
) {
|
// If our const destruct candidate is not ConstDestruct or implied by the param env,
|
||||||
// If our const destruct candidate is not ConstDestruct or implied by the param env,
|
// then it's bad
|
||||||
// then it's bad
|
return true;
|
||||||
return true;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if impl_src.borrow_nested_obligations().is_empty() {
|
if impl_src.borrow_nested_obligations().is_empty() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we had any errors, then it's bad
|
// If we had any errors, then it's bad
|
||||||
!traits::fully_solve_obligations(&infcx, impl_src.nested_obligations()).is_empty()
|
!traits::fully_solve_obligations(&infcx, impl_src.nested_obligations()).is_empty()
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn in_adt_inherently<'tcx>(
|
fn in_adt_inherently<'tcx>(
|
||||||
|
|
|
@ -105,7 +105,7 @@ pub fn equal_up_to_regions<'tcx>(
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
tcx.infer_ctxt().enter(|infcx| infcx.can_eq(param_env, normalize(src), normalize(dest)).is_ok())
|
tcx.infer_ctxt().build().can_eq(param_env, normalize(src), normalize(dest)).is_ok()
|
||||||
}
|
}
|
||||||
|
|
||||||
struct TypeChecker<'a, 'tcx> {
|
struct TypeChecker<'a, 'tcx> {
|
||||||
|
|
|
@ -83,9 +83,9 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
||||||
Res::Def(DefKind::TyParam, src_def_id) => {
|
Res::Def(DefKind::TyParam, src_def_id) => {
|
||||||
if let Some(param_local_id) = param.def_id.as_local() {
|
if let Some(param_local_id) = param.def_id.as_local() {
|
||||||
let param_name = tcx.hir().ty_param_name(param_local_id);
|
let param_name = tcx.hir().ty_param_name(param_local_id);
|
||||||
let param_type = tcx.infer_ctxt().enter(|infcx| {
|
let infcx = tcx.infer_ctxt().build();
|
||||||
infcx.resolve_numeric_literals_with_default(tcx.type_of(param.def_id))
|
let param_type =
|
||||||
});
|
infcx.resolve_numeric_literals_with_default(tcx.type_of(param.def_id));
|
||||||
if param_type.is_suggestable(tcx, false) {
|
if param_type.is_suggestable(tcx, false) {
|
||||||
err.span_suggestion(
|
err.span_suggestion(
|
||||||
tcx.def_span(src_def_id),
|
tcx.def_span(src_def_id),
|
||||||
|
|
|
@ -732,52 +732,52 @@ fn check_opaque_meets_bounds<'tcx>(
|
||||||
};
|
};
|
||||||
let param_env = tcx.param_env(defining_use_anchor);
|
let param_env = tcx.param_env(defining_use_anchor);
|
||||||
|
|
||||||
tcx.infer_ctxt().with_opaque_type_inference(DefiningAnchor::Bind(defining_use_anchor)).enter(
|
let infcx = tcx
|
||||||
move |infcx| {
|
.infer_ctxt()
|
||||||
let ocx = ObligationCtxt::new(&infcx);
|
.with_opaque_type_inference(DefiningAnchor::Bind(defining_use_anchor))
|
||||||
let opaque_ty = tcx.mk_opaque(def_id.to_def_id(), substs);
|
.build();
|
||||||
|
let ocx = ObligationCtxt::new(&infcx);
|
||||||
|
let opaque_ty = tcx.mk_opaque(def_id.to_def_id(), substs);
|
||||||
|
|
||||||
let misc_cause = traits::ObligationCause::misc(span, hir_id);
|
let misc_cause = traits::ObligationCause::misc(span, hir_id);
|
||||||
|
|
||||||
match infcx.at(&misc_cause, param_env).eq(opaque_ty, hidden_type) {
|
match infcx.at(&misc_cause, param_env).eq(opaque_ty, hidden_type) {
|
||||||
Ok(infer_ok) => ocx.register_infer_ok_obligations(infer_ok),
|
Ok(infer_ok) => ocx.register_infer_ok_obligations(infer_ok),
|
||||||
Err(ty_err) => {
|
Err(ty_err) => {
|
||||||
tcx.sess.delay_span_bug(
|
tcx.sess.delay_span_bug(
|
||||||
span,
|
span,
|
||||||
&format!("could not unify `{hidden_type}` with revealed type:\n{ty_err}"),
|
&format!("could not unify `{hidden_type}` with revealed type:\n{ty_err}"),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Additionally require the hidden type to be well-formed with only the generics of the opaque type.
|
// Additionally require the hidden type to be well-formed with only the generics of the opaque type.
|
||||||
// Defining use functions may have more bounds than the opaque type, which is ok, as long as the
|
// Defining use functions may have more bounds than the opaque type, which is ok, as long as the
|
||||||
// hidden type is well formed even without those bounds.
|
// hidden type is well formed even without those bounds.
|
||||||
let predicate = ty::Binder::dummy(ty::PredicateKind::WellFormed(hidden_type.into()))
|
let predicate =
|
||||||
.to_predicate(tcx);
|
ty::Binder::dummy(ty::PredicateKind::WellFormed(hidden_type.into())).to_predicate(tcx);
|
||||||
ocx.register_obligation(Obligation::new(misc_cause, param_env, predicate));
|
ocx.register_obligation(Obligation::new(misc_cause, param_env, predicate));
|
||||||
|
|
||||||
// Check that all obligations are satisfied by the implementation's
|
// Check that all obligations are satisfied by the implementation's
|
||||||
// version.
|
// version.
|
||||||
let errors = ocx.select_all_or_error();
|
let errors = ocx.select_all_or_error();
|
||||||
if !errors.is_empty() {
|
if !errors.is_empty() {
|
||||||
infcx.err_ctxt().report_fulfillment_errors(&errors, None, false);
|
infcx.err_ctxt().report_fulfillment_errors(&errors, None, false);
|
||||||
}
|
}
|
||||||
match origin {
|
match origin {
|
||||||
// Checked when type checking the function containing them.
|
// Checked when type checking the function containing them.
|
||||||
hir::OpaqueTyOrigin::FnReturn(..) | hir::OpaqueTyOrigin::AsyncFn(..) => {}
|
hir::OpaqueTyOrigin::FnReturn(..) | hir::OpaqueTyOrigin::AsyncFn(..) => {}
|
||||||
// Can have different predicates to their defining use
|
// Can have different predicates to their defining use
|
||||||
hir::OpaqueTyOrigin::TyAlias => {
|
hir::OpaqueTyOrigin::TyAlias => {
|
||||||
let outlives_environment = OutlivesEnvironment::new(param_env);
|
let outlives_environment = OutlivesEnvironment::new(param_env);
|
||||||
infcx.check_region_obligations_and_report_errors(
|
infcx.check_region_obligations_and_report_errors(
|
||||||
defining_use_anchor,
|
defining_use_anchor,
|
||||||
&outlives_environment,
|
&outlives_environment,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Clean up after ourselves
|
// Clean up after ourselves
|
||||||
let _ = infcx.inner.borrow_mut().opaque_type_storage.take_opaque_types();
|
let _ = infcx.inner.borrow_mut().opaque_type_storage.take_opaque_types();
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_item_type<'tcx>(tcx: TyCtxt<'tcx>, id: hir::ItemId) {
|
fn check_item_type<'tcx>(tcx: TyCtxt<'tcx>, id: hir::ItemId) {
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -876,18 +876,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
let ty = self.tcx.erase_late_bound_regions(Binder::bind_with_vars(ty, bound_vars));
|
let ty = self.tcx.erase_late_bound_regions(Binder::bind_with_vars(ty, bound_vars));
|
||||||
let ty = self.normalize_associated_types_in(expr.span, ty);
|
let ty = self.normalize_associated_types_in(expr.span, ty);
|
||||||
let ty = match self.tcx.asyncness(fn_id.owner) {
|
let ty = match self.tcx.asyncness(fn_id.owner) {
|
||||||
hir::IsAsync::Async => self
|
hir::IsAsync::Async => {
|
||||||
.tcx
|
let infcx = self.tcx.infer_ctxt().build();
|
||||||
.infer_ctxt()
|
infcx
|
||||||
.enter(|infcx| {
|
.get_impl_future_output_ty(ty)
|
||||||
infcx.get_impl_future_output_ty(ty).unwrap_or_else(|| {
|
.unwrap_or_else(|| {
|
||||||
span_bug!(
|
span_bug!(
|
||||||
fn_decl.output.span(),
|
fn_decl.output.span(),
|
||||||
"failed to get output type of async function"
|
"failed to get output type of async function"
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
})
|
.skip_binder()
|
||||||
.skip_binder(),
|
}
|
||||||
hir::IsAsync::NotAsync => ty,
|
hir::IsAsync::NotAsync => ty,
|
||||||
};
|
};
|
||||||
if self.can_coerce(found, ty) {
|
if self.can_coerce(found, ty) {
|
||||||
|
|
|
@ -129,7 +129,7 @@ impl<'tcx> InheritedBuilder<'tcx> {
|
||||||
F: FnOnce(&Inherited<'tcx>) -> R,
|
F: FnOnce(&Inherited<'tcx>) -> R,
|
||||||
{
|
{
|
||||||
let def_id = self.def_id;
|
let def_id = self.def_id;
|
||||||
self.infcx.enter(|infcx| f(&Inherited::new(infcx, def_id, self.typeck_results)))
|
f(&Inherited::new(self.infcx.build(), def_id, self.typeck_results))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -472,69 +472,65 @@ fn method_autoderef_steps<'tcx>(
|
||||||
) -> MethodAutoderefStepsResult<'tcx> {
|
) -> MethodAutoderefStepsResult<'tcx> {
|
||||||
debug!("method_autoderef_steps({:?})", goal);
|
debug!("method_autoderef_steps({:?})", goal);
|
||||||
|
|
||||||
tcx.infer_ctxt().enter_with_canonical(DUMMY_SP, &goal, |ref infcx, goal, inference_vars| {
|
let (ref infcx, goal, inference_vars) = tcx.infer_ctxt().build_with_canonical(DUMMY_SP, &goal);
|
||||||
let ParamEnvAnd { param_env, value: self_ty } = goal;
|
let ParamEnvAnd { param_env, value: self_ty } = goal;
|
||||||
|
|
||||||
let mut autoderef =
|
let mut autoderef =
|
||||||
Autoderef::new(infcx, param_env, hir::CRATE_HIR_ID, DUMMY_SP, self_ty, DUMMY_SP)
|
Autoderef::new(infcx, param_env, hir::CRATE_HIR_ID, DUMMY_SP, self_ty, DUMMY_SP)
|
||||||
.include_raw_pointers()
|
.include_raw_pointers()
|
||||||
.silence_errors();
|
.silence_errors();
|
||||||
let mut reached_raw_pointer = false;
|
let mut reached_raw_pointer = false;
|
||||||
let mut steps: Vec<_> = autoderef
|
let mut steps: Vec<_> = autoderef
|
||||||
.by_ref()
|
.by_ref()
|
||||||
.map(|(ty, d)| {
|
.map(|(ty, d)| {
|
||||||
let step = CandidateStep {
|
let step = CandidateStep {
|
||||||
self_ty: infcx.make_query_response_ignoring_pending_obligations(
|
self_ty: infcx
|
||||||
inference_vars.clone(),
|
.make_query_response_ignoring_pending_obligations(inference_vars.clone(), ty),
|
||||||
ty,
|
autoderefs: d,
|
||||||
),
|
from_unsafe_deref: reached_raw_pointer,
|
||||||
autoderefs: d,
|
unsize: false,
|
||||||
from_unsafe_deref: reached_raw_pointer,
|
};
|
||||||
unsize: false,
|
if let ty::RawPtr(_) = ty.kind() {
|
||||||
};
|
// all the subsequent steps will be from_unsafe_deref
|
||||||
if let ty::RawPtr(_) = ty.kind() {
|
reached_raw_pointer = true;
|
||||||
// all the subsequent steps will be from_unsafe_deref
|
|
||||||
reached_raw_pointer = true;
|
|
||||||
}
|
|
||||||
step
|
|
||||||
})
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
let final_ty = autoderef.final_ty(true);
|
|
||||||
let opt_bad_ty = match final_ty.kind() {
|
|
||||||
ty::Infer(ty::TyVar(_)) | ty::Error(_) => Some(MethodAutoderefBadTy {
|
|
||||||
reached_raw_pointer,
|
|
||||||
ty: infcx
|
|
||||||
.make_query_response_ignoring_pending_obligations(inference_vars, final_ty),
|
|
||||||
}),
|
|
||||||
ty::Array(elem_ty, _) => {
|
|
||||||
let dereferences = steps.len() - 1;
|
|
||||||
|
|
||||||
steps.push(CandidateStep {
|
|
||||||
self_ty: infcx.make_query_response_ignoring_pending_obligations(
|
|
||||||
inference_vars,
|
|
||||||
infcx.tcx.mk_slice(*elem_ty),
|
|
||||||
),
|
|
||||||
autoderefs: dereferences,
|
|
||||||
// this could be from an unsafe deref if we had
|
|
||||||
// a *mut/const [T; N]
|
|
||||||
from_unsafe_deref: reached_raw_pointer,
|
|
||||||
unsize: true,
|
|
||||||
});
|
|
||||||
|
|
||||||
None
|
|
||||||
}
|
}
|
||||||
_ => None,
|
step
|
||||||
};
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
debug!("method_autoderef_steps: steps={:?} opt_bad_ty={:?}", steps, opt_bad_ty);
|
let final_ty = autoderef.final_ty(true);
|
||||||
|
let opt_bad_ty = match final_ty.kind() {
|
||||||
|
ty::Infer(ty::TyVar(_)) | ty::Error(_) => Some(MethodAutoderefBadTy {
|
||||||
|
reached_raw_pointer,
|
||||||
|
ty: infcx.make_query_response_ignoring_pending_obligations(inference_vars, final_ty),
|
||||||
|
}),
|
||||||
|
ty::Array(elem_ty, _) => {
|
||||||
|
let dereferences = steps.len() - 1;
|
||||||
|
|
||||||
MethodAutoderefStepsResult {
|
steps.push(CandidateStep {
|
||||||
steps: tcx.arena.alloc_from_iter(steps),
|
self_ty: infcx.make_query_response_ignoring_pending_obligations(
|
||||||
opt_bad_ty: opt_bad_ty.map(|ty| &*tcx.arena.alloc(ty)),
|
inference_vars,
|
||||||
reached_recursion_limit: autoderef.reached_recursion_limit(),
|
infcx.tcx.mk_slice(*elem_ty),
|
||||||
|
),
|
||||||
|
autoderefs: dereferences,
|
||||||
|
// this could be from an unsafe deref if we had
|
||||||
|
// a *mut/const [T; N]
|
||||||
|
from_unsafe_deref: reached_raw_pointer,
|
||||||
|
unsize: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
None
|
||||||
}
|
}
|
||||||
})
|
_ => None,
|
||||||
|
};
|
||||||
|
|
||||||
|
debug!("method_autoderef_steps: steps={:?} opt_bad_ty={:?}", steps, opt_bad_ty);
|
||||||
|
|
||||||
|
MethodAutoderefStepsResult {
|
||||||
|
steps: tcx.arena.alloc_from_iter(steps),
|
||||||
|
opt_bad_ty: opt_bad_ty.map(|ty| &*tcx.arena.alloc(ty)),
|
||||||
|
reached_recursion_limit: autoderef.reached_recursion_limit(),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
|
impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
|
||||||
|
|
|
@ -91,29 +91,28 @@ pub(super) fn enter_wf_checking_ctxt<'tcx, F>(
|
||||||
{
|
{
|
||||||
let param_env = tcx.param_env(body_def_id);
|
let param_env = tcx.param_env(body_def_id);
|
||||||
let body_id = tcx.hir().local_def_id_to_hir_id(body_def_id);
|
let body_id = tcx.hir().local_def_id_to_hir_id(body_def_id);
|
||||||
tcx.infer_ctxt().enter(|ref infcx| {
|
let infcx = &tcx.infer_ctxt().build();
|
||||||
let ocx = ObligationCtxt::new(infcx);
|
let ocx = ObligationCtxt::new(infcx);
|
||||||
|
|
||||||
let assumed_wf_types = ocx.assumed_wf_types(param_env, span, body_def_id);
|
let assumed_wf_types = ocx.assumed_wf_types(param_env, span, body_def_id);
|
||||||
|
|
||||||
let mut wfcx = WfCheckingCtxt { ocx, span, body_id, param_env };
|
let mut wfcx = WfCheckingCtxt { ocx, span, body_id, param_env };
|
||||||
|
|
||||||
if !tcx.features().trivial_bounds {
|
if !tcx.features().trivial_bounds {
|
||||||
wfcx.check_false_global_bounds()
|
wfcx.check_false_global_bounds()
|
||||||
}
|
}
|
||||||
f(&mut wfcx);
|
f(&mut wfcx);
|
||||||
let errors = wfcx.select_all_or_error();
|
let errors = wfcx.select_all_or_error();
|
||||||
if !errors.is_empty() {
|
if !errors.is_empty() {
|
||||||
infcx.err_ctxt().report_fulfillment_errors(&errors, None, false);
|
infcx.err_ctxt().report_fulfillment_errors(&errors, None, false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let implied_bounds = infcx.implied_bounds_tys(param_env, body_id, assumed_wf_types);
|
let implied_bounds = infcx.implied_bounds_tys(param_env, body_id, assumed_wf_types);
|
||||||
let outlives_environment =
|
let outlives_environment =
|
||||||
OutlivesEnvironment::with_bounds(param_env, Some(infcx), implied_bounds);
|
OutlivesEnvironment::with_bounds(param_env, Some(infcx), implied_bounds);
|
||||||
|
|
||||||
infcx.check_region_obligations_and_report_errors(body_def_id, &outlives_environment);
|
infcx.check_region_obligations_and_report_errors(body_def_id, &outlives_environment);
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_well_formed(tcx: TyCtxt<'_>, def_id: hir::OwnerId) {
|
fn check_well_formed(tcx: TyCtxt<'_>, def_id: hir::OwnerId) {
|
||||||
|
@ -704,24 +703,23 @@ fn resolve_regions_with_wf_tys<'tcx>(
|
||||||
// Unfortunately, we have to use a new `InferCtxt` each call, because
|
// Unfortunately, we have to use a new `InferCtxt` each call, because
|
||||||
// region constraints get added and solved there and we need to test each
|
// region constraints get added and solved there and we need to test each
|
||||||
// call individually.
|
// call individually.
|
||||||
tcx.infer_ctxt().enter(|infcx| {
|
let infcx = tcx.infer_ctxt().build();
|
||||||
let outlives_environment = OutlivesEnvironment::with_bounds(
|
let outlives_environment = OutlivesEnvironment::with_bounds(
|
||||||
param_env,
|
param_env,
|
||||||
Some(&infcx),
|
Some(&infcx),
|
||||||
infcx.implied_bounds_tys(param_env, id, wf_tys.clone()),
|
infcx.implied_bounds_tys(param_env, id, wf_tys.clone()),
|
||||||
);
|
);
|
||||||
let region_bound_pairs = outlives_environment.region_bound_pairs();
|
let region_bound_pairs = outlives_environment.region_bound_pairs();
|
||||||
|
|
||||||
add_constraints(&infcx, region_bound_pairs);
|
add_constraints(&infcx, region_bound_pairs);
|
||||||
|
|
||||||
let errors = infcx.resolve_regions(&outlives_environment);
|
let errors = infcx.resolve_regions(&outlives_environment);
|
||||||
|
|
||||||
debug!(?errors, "errors");
|
debug!(?errors, "errors");
|
||||||
|
|
||||||
// If we were able to prove that the type outlives the region without
|
// If we were able to prove that the type outlives the region without
|
||||||
// an error, it must be because of the implied or explicit bounds...
|
// an error, it must be because of the implied or explicit bounds...
|
||||||
errors.is_empty()
|
errors.is_empty()
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// TypeVisitor that looks for uses of GATs like
|
/// TypeVisitor that looks for uses of GATs like
|
||||||
|
|
|
@ -108,43 +108,42 @@ fn visit_implementation_of_copy(tcx: TyCtxt<'_>, impl_did: LocalDefId) {
|
||||||
// why this field does not implement Copy. This is useful because sometimes
|
// why this field does not implement Copy. This is useful because sometimes
|
||||||
// it is not immediately clear why Copy is not implemented for a field, since
|
// it is not immediately clear why Copy is not implemented for a field, since
|
||||||
// all we point at is the field itself.
|
// all we point at is the field itself.
|
||||||
tcx.infer_ctxt().ignoring_regions().enter(|infcx| {
|
let infcx = tcx.infer_ctxt().ignoring_regions().build();
|
||||||
for error in traits::fully_solve_bound(
|
for error in traits::fully_solve_bound(
|
||||||
&infcx,
|
&infcx,
|
||||||
traits::ObligationCause::dummy_with_span(field_ty_span),
|
traits::ObligationCause::dummy_with_span(field_ty_span),
|
||||||
param_env,
|
param_env,
|
||||||
ty,
|
ty,
|
||||||
tcx.lang_items().copy_trait().unwrap(),
|
tcx.lang_items().copy_trait().unwrap(),
|
||||||
) {
|
) {
|
||||||
let error_predicate = error.obligation.predicate;
|
let error_predicate = error.obligation.predicate;
|
||||||
// Only note if it's not the root obligation, otherwise it's trivial and
|
// Only note if it's not the root obligation, otherwise it's trivial and
|
||||||
// should be self-explanatory (i.e. a field literally doesn't implement Copy).
|
// should be self-explanatory (i.e. a field literally doesn't implement Copy).
|
||||||
|
|
||||||
// FIXME: This error could be more descriptive, especially if the error_predicate
|
// FIXME: This error could be more descriptive, especially if the error_predicate
|
||||||
// contains a foreign type or if it's a deeply nested type...
|
// contains a foreign type or if it's a deeply nested type...
|
||||||
if error_predicate != error.root_obligation.predicate {
|
if error_predicate != error.root_obligation.predicate {
|
||||||
errors
|
errors
|
||||||
.entry((ty.to_string(), error_predicate.to_string()))
|
.entry((ty.to_string(), error_predicate.to_string()))
|
||||||
.or_default()
|
.or_default()
|
||||||
.push(error.obligation.cause.span);
|
.push(error.obligation.cause.span);
|
||||||
}
|
}
|
||||||
if let ty::PredicateKind::Trait(ty::TraitPredicate {
|
if let ty::PredicateKind::Trait(ty::TraitPredicate {
|
||||||
trait_ref,
|
trait_ref,
|
||||||
polarity: ty::ImplPolarity::Positive,
|
polarity: ty::ImplPolarity::Positive,
|
||||||
..
|
..
|
||||||
}) = error_predicate.kind().skip_binder()
|
}) = error_predicate.kind().skip_binder()
|
||||||
{
|
{
|
||||||
let ty = trait_ref.self_ty();
|
let ty = trait_ref.self_ty();
|
||||||
if let ty::Param(_) = ty.kind() {
|
if let ty::Param(_) = ty.kind() {
|
||||||
bounds.push((
|
bounds.push((
|
||||||
format!("{ty}"),
|
format!("{ty}"),
|
||||||
trait_ref.print_only_trait_path().to_string(),
|
trait_ref.print_only_trait_path().to_string(),
|
||||||
Some(trait_ref.def_id),
|
Some(trait_ref.def_id),
|
||||||
));
|
));
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
}
|
}
|
||||||
for ((ty, error_predicate), spans) in errors {
|
for ((ty, error_predicate), spans) in errors {
|
||||||
let span: MultiSpan = spans.into();
|
let span: MultiSpan = spans.into();
|
||||||
|
@ -205,91 +204,89 @@ fn visit_implementation_of_dispatch_from_dyn<'tcx>(tcx: TyCtxt<'tcx>, impl_did:
|
||||||
|
|
||||||
let create_err = |msg: &str| struct_span_err!(tcx.sess, span, E0378, "{}", msg);
|
let create_err = |msg: &str| struct_span_err!(tcx.sess, span, E0378, "{}", msg);
|
||||||
|
|
||||||
tcx.infer_ctxt().enter(|infcx| {
|
let infcx = tcx.infer_ctxt().build();
|
||||||
let cause = ObligationCause::misc(span, impl_hir_id);
|
let cause = ObligationCause::misc(span, impl_hir_id);
|
||||||
|
|
||||||
use rustc_type_ir::sty::TyKind::*;
|
use rustc_type_ir::sty::TyKind::*;
|
||||||
match (source.kind(), target.kind()) {
|
match (source.kind(), target.kind()) {
|
||||||
(&Ref(r_a, _, mutbl_a), Ref(r_b, _, mutbl_b))
|
(&Ref(r_a, _, mutbl_a), Ref(r_b, _, mutbl_b))
|
||||||
if infcx.at(&cause, param_env).eq(r_a, *r_b).is_ok() && mutbl_a == *mutbl_b => {}
|
if infcx.at(&cause, param_env).eq(r_a, *r_b).is_ok() && mutbl_a == *mutbl_b => {}
|
||||||
(&RawPtr(tm_a), &RawPtr(tm_b)) if tm_a.mutbl == tm_b.mutbl => (),
|
(&RawPtr(tm_a), &RawPtr(tm_b)) if tm_a.mutbl == tm_b.mutbl => (),
|
||||||
(&Adt(def_a, substs_a), &Adt(def_b, substs_b))
|
(&Adt(def_a, substs_a), &Adt(def_b, substs_b))
|
||||||
if def_a.is_struct() && def_b.is_struct() =>
|
if def_a.is_struct() && def_b.is_struct() =>
|
||||||
{
|
{
|
||||||
if def_a != def_b {
|
if def_a != def_b {
|
||||||
let source_path = tcx.def_path_str(def_a.did());
|
let source_path = tcx.def_path_str(def_a.did());
|
||||||
let target_path = tcx.def_path_str(def_b.did());
|
let target_path = tcx.def_path_str(def_b.did());
|
||||||
|
|
||||||
create_err(&format!(
|
create_err(&format!(
|
||||||
"the trait `DispatchFromDyn` may only be implemented \
|
"the trait `DispatchFromDyn` may only be implemented \
|
||||||
for a coercion between structures with the same \
|
for a coercion between structures with the same \
|
||||||
definition; expected `{}`, found `{}`",
|
definition; expected `{}`, found `{}`",
|
||||||
source_path, target_path,
|
source_path, target_path,
|
||||||
))
|
))
|
||||||
.emit();
|
.emit();
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if def_a.repr().c() || def_a.repr().packed() {
|
if def_a.repr().c() || def_a.repr().packed() {
|
||||||
create_err(
|
create_err(
|
||||||
"structs implementing `DispatchFromDyn` may not have \
|
"structs implementing `DispatchFromDyn` may not have \
|
||||||
`#[repr(packed)]` or `#[repr(C)]`",
|
`#[repr(packed)]` or `#[repr(C)]`",
|
||||||
)
|
)
|
||||||
.emit();
|
.emit();
|
||||||
}
|
}
|
||||||
|
|
||||||
let fields = &def_a.non_enum_variant().fields;
|
let fields = &def_a.non_enum_variant().fields;
|
||||||
|
|
||||||
let coerced_fields = fields
|
let coerced_fields = fields
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|field| {
|
.filter(|field| {
|
||||||
let ty_a = field.ty(tcx, substs_a);
|
let ty_a = field.ty(tcx, substs_a);
|
||||||
let ty_b = field.ty(tcx, substs_b);
|
let ty_b = field.ty(tcx, substs_b);
|
||||||
|
|
||||||
if let Ok(layout) = tcx.layout_of(param_env.and(ty_a)) {
|
if let Ok(layout) = tcx.layout_of(param_env.and(ty_a)) {
|
||||||
if layout.is_zst() && layout.align.abi.bytes() == 1 {
|
if layout.is_zst() && layout.align.abi.bytes() == 1 {
|
||||||
// ignore ZST fields with alignment of 1 byte
|
// ignore ZST fields with alignment of 1 byte
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if let Ok(ok) = infcx.at(&cause, param_env).eq(ty_a, ty_b) {
|
if let Ok(ok) = infcx.at(&cause, param_env).eq(ty_a, ty_b) {
|
||||||
if ok.obligations.is_empty() {
|
if ok.obligations.is_empty() {
|
||||||
create_err(
|
create_err(
|
||||||
"the trait `DispatchFromDyn` may only be implemented \
|
"the trait `DispatchFromDyn` may only be implemented \
|
||||||
for structs containing the field being coerced, \
|
for structs containing the field being coerced, \
|
||||||
ZST fields with 1 byte alignment, and nothing else",
|
ZST fields with 1 byte alignment, and nothing else",
|
||||||
)
|
)
|
||||||
.note(&format!(
|
.note(&format!(
|
||||||
"extra field `{}` of type `{}` is not allowed",
|
"extra field `{}` of type `{}` is not allowed",
|
||||||
field.name, ty_a,
|
field.name, ty_a,
|
||||||
))
|
))
|
||||||
.emit();
|
.emit();
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
})
|
})
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
if coerced_fields.is_empty() {
|
if coerced_fields.is_empty() {
|
||||||
create_err(
|
create_err(
|
||||||
"the trait `DispatchFromDyn` may only be implemented \
|
"the trait `DispatchFromDyn` may only be implemented \
|
||||||
for a coercion between structures with a single field \
|
for a coercion between structures with a single field \
|
||||||
being coerced, none found",
|
being coerced, none found",
|
||||||
)
|
)
|
||||||
.emit();
|
.emit();
|
||||||
} else if coerced_fields.len() > 1 {
|
} else if coerced_fields.len() > 1 {
|
||||||
create_err(
|
create_err("implementing the `DispatchFromDyn` trait requires multiple coercions")
|
||||||
"implementing the `DispatchFromDyn` trait requires multiple coercions",
|
|
||||||
)
|
|
||||||
.note(
|
.note(
|
||||||
"the trait `DispatchFromDyn` may only be implemented \
|
"the trait `DispatchFromDyn` may only be implemented \
|
||||||
for a coercion between structures with a single field \
|
for a coercion between structures with a single field \
|
||||||
being coerced",
|
being coerced",
|
||||||
)
|
)
|
||||||
.note(&format!(
|
.note(&format!(
|
||||||
"currently, {} fields need coercions: {}",
|
"currently, {} fields need coercions: {}",
|
||||||
|
@ -308,39 +305,38 @@ fn visit_implementation_of_dispatch_from_dyn<'tcx>(tcx: TyCtxt<'tcx>, impl_did:
|
||||||
.join(", ")
|
.join(", ")
|
||||||
))
|
))
|
||||||
.emit();
|
.emit();
|
||||||
} else {
|
} else {
|
||||||
let errors = traits::fully_solve_obligations(
|
let errors = traits::fully_solve_obligations(
|
||||||
&infcx,
|
&infcx,
|
||||||
coerced_fields.into_iter().map(|field| {
|
coerced_fields.into_iter().map(|field| {
|
||||||
predicate_for_trait_def(
|
predicate_for_trait_def(
|
||||||
tcx,
|
tcx,
|
||||||
param_env,
|
param_env,
|
||||||
cause.clone(),
|
cause.clone(),
|
||||||
dispatch_from_dyn_trait,
|
dispatch_from_dyn_trait,
|
||||||
0,
|
0,
|
||||||
field.ty(tcx, substs_a),
|
field.ty(tcx, substs_a),
|
||||||
&[field.ty(tcx, substs_b).into()],
|
&[field.ty(tcx, substs_b).into()],
|
||||||
)
|
)
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
if !errors.is_empty() {
|
if !errors.is_empty() {
|
||||||
infcx.err_ctxt().report_fulfillment_errors(&errors, None, false);
|
infcx.err_ctxt().report_fulfillment_errors(&errors, None, false);
|
||||||
}
|
|
||||||
|
|
||||||
// Finally, resolve all regions.
|
|
||||||
let outlives_env = OutlivesEnvironment::new(param_env);
|
|
||||||
infcx.check_region_obligations_and_report_errors(impl_did, &outlives_env);
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
_ => {
|
// Finally, resolve all regions.
|
||||||
create_err(
|
let outlives_env = OutlivesEnvironment::new(param_env);
|
||||||
"the trait `DispatchFromDyn` may only be implemented \
|
infcx.check_region_obligations_and_report_errors(impl_did, &outlives_env);
|
||||||
for a coercion between structures",
|
|
||||||
)
|
|
||||||
.emit();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
_ => {
|
||||||
|
create_err(
|
||||||
|
"the trait `DispatchFromDyn` may only be implemented \
|
||||||
|
for a coercion between structures",
|
||||||
|
)
|
||||||
|
.emit();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn coerce_unsized_info<'tcx>(tcx: TyCtxt<'tcx>, impl_did: DefId) -> CoerceUnsizedInfo {
|
pub fn coerce_unsized_info<'tcx>(tcx: TyCtxt<'tcx>, impl_did: DefId) -> CoerceUnsizedInfo {
|
||||||
|
@ -369,221 +365,208 @@ pub fn coerce_unsized_info<'tcx>(tcx: TyCtxt<'tcx>, impl_did: DefId) -> CoerceUn
|
||||||
|
|
||||||
debug!("visit_implementation_of_coerce_unsized: {:?} -> {:?} (free)", source, target);
|
debug!("visit_implementation_of_coerce_unsized: {:?} -> {:?} (free)", source, target);
|
||||||
|
|
||||||
tcx.infer_ctxt().enter(|infcx| {
|
let infcx = tcx.infer_ctxt().build();
|
||||||
let impl_hir_id = tcx.hir().local_def_id_to_hir_id(impl_did);
|
let impl_hir_id = tcx.hir().local_def_id_to_hir_id(impl_did);
|
||||||
let cause = ObligationCause::misc(span, impl_hir_id);
|
let cause = ObligationCause::misc(span, impl_hir_id);
|
||||||
let check_mutbl = |mt_a: ty::TypeAndMut<'tcx>,
|
let check_mutbl = |mt_a: ty::TypeAndMut<'tcx>,
|
||||||
mt_b: ty::TypeAndMut<'tcx>,
|
mt_b: ty::TypeAndMut<'tcx>,
|
||||||
mk_ptr: &dyn Fn(Ty<'tcx>) -> Ty<'tcx>| {
|
mk_ptr: &dyn Fn(Ty<'tcx>) -> Ty<'tcx>| {
|
||||||
if (mt_a.mutbl, mt_b.mutbl) == (hir::Mutability::Not, hir::Mutability::Mut) {
|
if (mt_a.mutbl, mt_b.mutbl) == (hir::Mutability::Not, hir::Mutability::Mut) {
|
||||||
infcx
|
infcx
|
||||||
.err_ctxt()
|
.err_ctxt()
|
||||||
.report_mismatched_types(
|
.report_mismatched_types(
|
||||||
&cause,
|
&cause,
|
||||||
mk_ptr(mt_b.ty),
|
mk_ptr(mt_b.ty),
|
||||||
target,
|
target,
|
||||||
ty::error::TypeError::Mutability,
|
ty::error::TypeError::Mutability,
|
||||||
)
|
)
|
||||||
.emit();
|
.emit();
|
||||||
}
|
}
|
||||||
(mt_a.ty, mt_b.ty, unsize_trait, None)
|
(mt_a.ty, mt_b.ty, unsize_trait, None)
|
||||||
};
|
};
|
||||||
let (source, target, trait_def_id, kind) = match (source.kind(), target.kind()) {
|
let (source, target, trait_def_id, kind) = match (source.kind(), target.kind()) {
|
||||||
(&ty::Ref(r_a, ty_a, mutbl_a), &ty::Ref(r_b, ty_b, mutbl_b)) => {
|
(&ty::Ref(r_a, ty_a, mutbl_a), &ty::Ref(r_b, ty_b, mutbl_b)) => {
|
||||||
infcx.sub_regions(infer::RelateObjectBound(span), r_b, r_a);
|
infcx.sub_regions(infer::RelateObjectBound(span), r_b, r_a);
|
||||||
let mt_a = ty::TypeAndMut { ty: ty_a, mutbl: mutbl_a };
|
let mt_a = ty::TypeAndMut { ty: ty_a, mutbl: mutbl_a };
|
||||||
let mt_b = ty::TypeAndMut { ty: ty_b, mutbl: mutbl_b };
|
let mt_b = ty::TypeAndMut { ty: ty_b, mutbl: mutbl_b };
|
||||||
check_mutbl(mt_a, mt_b, &|ty| tcx.mk_imm_ref(r_b, ty))
|
check_mutbl(mt_a, mt_b, &|ty| tcx.mk_imm_ref(r_b, ty))
|
||||||
|
}
|
||||||
|
|
||||||
|
(&ty::Ref(_, ty_a, mutbl_a), &ty::RawPtr(mt_b)) => {
|
||||||
|
let mt_a = ty::TypeAndMut { ty: ty_a, mutbl: mutbl_a };
|
||||||
|
check_mutbl(mt_a, mt_b, &|ty| tcx.mk_imm_ptr(ty))
|
||||||
|
}
|
||||||
|
|
||||||
|
(&ty::RawPtr(mt_a), &ty::RawPtr(mt_b)) => check_mutbl(mt_a, mt_b, &|ty| tcx.mk_imm_ptr(ty)),
|
||||||
|
|
||||||
|
(&ty::Adt(def_a, substs_a), &ty::Adt(def_b, substs_b))
|
||||||
|
if def_a.is_struct() && def_b.is_struct() =>
|
||||||
|
{
|
||||||
|
if def_a != def_b {
|
||||||
|
let source_path = tcx.def_path_str(def_a.did());
|
||||||
|
let target_path = tcx.def_path_str(def_b.did());
|
||||||
|
struct_span_err!(
|
||||||
|
tcx.sess,
|
||||||
|
span,
|
||||||
|
E0377,
|
||||||
|
"the trait `CoerceUnsized` may only be implemented \
|
||||||
|
for a coercion between structures with the same \
|
||||||
|
definition; expected `{}`, found `{}`",
|
||||||
|
source_path,
|
||||||
|
target_path
|
||||||
|
)
|
||||||
|
.emit();
|
||||||
|
return err_info;
|
||||||
}
|
}
|
||||||
|
|
||||||
(&ty::Ref(_, ty_a, mutbl_a), &ty::RawPtr(mt_b)) => {
|
// Here we are considering a case of converting
|
||||||
let mt_a = ty::TypeAndMut { ty: ty_a, mutbl: mutbl_a };
|
// `S<P0...Pn>` to S<Q0...Qn>`. As an example, let's imagine a struct `Foo<T, U>`,
|
||||||
check_mutbl(mt_a, mt_b, &|ty| tcx.mk_imm_ptr(ty))
|
// which acts like a pointer to `U`, but carries along some extra data of type `T`:
|
||||||
}
|
//
|
||||||
|
// struct Foo<T, U> {
|
||||||
|
// extra: T,
|
||||||
|
// ptr: *mut U,
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// We might have an impl that allows (e.g.) `Foo<T, [i32; 3]>` to be unsized
|
||||||
|
// to `Foo<T, [i32]>`. That impl would look like:
|
||||||
|
//
|
||||||
|
// impl<T, U: Unsize<V>, V> CoerceUnsized<Foo<T, V>> for Foo<T, U> {}
|
||||||
|
//
|
||||||
|
// Here `U = [i32; 3]` and `V = [i32]`. At runtime,
|
||||||
|
// when this coercion occurs, we would be changing the
|
||||||
|
// field `ptr` from a thin pointer of type `*mut [i32;
|
||||||
|
// 3]` to a fat pointer of type `*mut [i32]` (with
|
||||||
|
// extra data `3`). **The purpose of this check is to
|
||||||
|
// make sure that we know how to do this conversion.**
|
||||||
|
//
|
||||||
|
// To check if this impl is legal, we would walk down
|
||||||
|
// the fields of `Foo` and consider their types with
|
||||||
|
// both substitutes. We are looking to find that
|
||||||
|
// exactly one (non-phantom) field has changed its
|
||||||
|
// type, which we will expect to be the pointer that
|
||||||
|
// is becoming fat (we could probably generalize this
|
||||||
|
// to multiple thin pointers of the same type becoming
|
||||||
|
// fat, but we don't). In this case:
|
||||||
|
//
|
||||||
|
// - `extra` has type `T` before and type `T` after
|
||||||
|
// - `ptr` has type `*mut U` before and type `*mut V` after
|
||||||
|
//
|
||||||
|
// Since just one field changed, we would then check
|
||||||
|
// that `*mut U: CoerceUnsized<*mut V>` is implemented
|
||||||
|
// (in other words, that we know how to do this
|
||||||
|
// conversion). This will work out because `U:
|
||||||
|
// Unsize<V>`, and we have a builtin rule that `*mut
|
||||||
|
// U` can be coerced to `*mut V` if `U: Unsize<V>`.
|
||||||
|
let fields = &def_a.non_enum_variant().fields;
|
||||||
|
let diff_fields = fields
|
||||||
|
.iter()
|
||||||
|
.enumerate()
|
||||||
|
.filter_map(|(i, f)| {
|
||||||
|
let (a, b) = (f.ty(tcx, substs_a), f.ty(tcx, substs_b));
|
||||||
|
|
||||||
(&ty::RawPtr(mt_a), &ty::RawPtr(mt_b)) => {
|
if tcx.type_of(f.did).is_phantom_data() {
|
||||||
check_mutbl(mt_a, mt_b, &|ty| tcx.mk_imm_ptr(ty))
|
// Ignore PhantomData fields
|
||||||
}
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
(&ty::Adt(def_a, substs_a), &ty::Adt(def_b, substs_b))
|
// Ignore fields that aren't changed; it may
|
||||||
if def_a.is_struct() && def_b.is_struct() =>
|
// be that we could get away with subtyping or
|
||||||
{
|
// something more accepting, but we use
|
||||||
if def_a != def_b {
|
// equality because we want to be able to
|
||||||
let source_path = tcx.def_path_str(def_a.did());
|
// perform this check without computing
|
||||||
let target_path = tcx.def_path_str(def_b.did());
|
// variance where possible. (This is because
|
||||||
struct_span_err!(
|
// we may have to evaluate constraint
|
||||||
tcx.sess,
|
// expressions in the course of execution.)
|
||||||
span,
|
// See e.g., #41936.
|
||||||
E0377,
|
if let Ok(ok) = infcx.at(&cause, param_env).eq(a, b) {
|
||||||
"the trait `CoerceUnsized` may only be implemented \
|
if ok.obligations.is_empty() {
|
||||||
for a coercion between structures with the same \
|
|
||||||
definition; expected `{}`, found `{}`",
|
|
||||||
source_path,
|
|
||||||
target_path
|
|
||||||
)
|
|
||||||
.emit();
|
|
||||||
return err_info;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Here we are considering a case of converting
|
|
||||||
// `S<P0...Pn>` to S<Q0...Qn>`. As an example, let's imagine a struct `Foo<T, U>`,
|
|
||||||
// which acts like a pointer to `U`, but carries along some extra data of type `T`:
|
|
||||||
//
|
|
||||||
// struct Foo<T, U> {
|
|
||||||
// extra: T,
|
|
||||||
// ptr: *mut U,
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// We might have an impl that allows (e.g.) `Foo<T, [i32; 3]>` to be unsized
|
|
||||||
// to `Foo<T, [i32]>`. That impl would look like:
|
|
||||||
//
|
|
||||||
// impl<T, U: Unsize<V>, V> CoerceUnsized<Foo<T, V>> for Foo<T, U> {}
|
|
||||||
//
|
|
||||||
// Here `U = [i32; 3]` and `V = [i32]`. At runtime,
|
|
||||||
// when this coercion occurs, we would be changing the
|
|
||||||
// field `ptr` from a thin pointer of type `*mut [i32;
|
|
||||||
// 3]` to a fat pointer of type `*mut [i32]` (with
|
|
||||||
// extra data `3`). **The purpose of this check is to
|
|
||||||
// make sure that we know how to do this conversion.**
|
|
||||||
//
|
|
||||||
// To check if this impl is legal, we would walk down
|
|
||||||
// the fields of `Foo` and consider their types with
|
|
||||||
// both substitutes. We are looking to find that
|
|
||||||
// exactly one (non-phantom) field has changed its
|
|
||||||
// type, which we will expect to be the pointer that
|
|
||||||
// is becoming fat (we could probably generalize this
|
|
||||||
// to multiple thin pointers of the same type becoming
|
|
||||||
// fat, but we don't). In this case:
|
|
||||||
//
|
|
||||||
// - `extra` has type `T` before and type `T` after
|
|
||||||
// - `ptr` has type `*mut U` before and type `*mut V` after
|
|
||||||
//
|
|
||||||
// Since just one field changed, we would then check
|
|
||||||
// that `*mut U: CoerceUnsized<*mut V>` is implemented
|
|
||||||
// (in other words, that we know how to do this
|
|
||||||
// conversion). This will work out because `U:
|
|
||||||
// Unsize<V>`, and we have a builtin rule that `*mut
|
|
||||||
// U` can be coerced to `*mut V` if `U: Unsize<V>`.
|
|
||||||
let fields = &def_a.non_enum_variant().fields;
|
|
||||||
let diff_fields = fields
|
|
||||||
.iter()
|
|
||||||
.enumerate()
|
|
||||||
.filter_map(|(i, f)| {
|
|
||||||
let (a, b) = (f.ty(tcx, substs_a), f.ty(tcx, substs_b));
|
|
||||||
|
|
||||||
if tcx.type_of(f.did).is_phantom_data() {
|
|
||||||
// Ignore PhantomData fields
|
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Ignore fields that aren't changed; it may
|
// Collect up all fields that were significantly changed
|
||||||
// be that we could get away with subtyping or
|
// i.e., those that contain T in coerce_unsized T -> U
|
||||||
// something more accepting, but we use
|
Some((i, a, b))
|
||||||
// equality because we want to be able to
|
})
|
||||||
// perform this check without computing
|
.collect::<Vec<_>>();
|
||||||
// variance where possible. (This is because
|
|
||||||
// we may have to evaluate constraint
|
|
||||||
// expressions in the course of execution.)
|
|
||||||
// See e.g., #41936.
|
|
||||||
if let Ok(ok) = infcx.at(&cause, param_env).eq(a, b) {
|
|
||||||
if ok.obligations.is_empty() {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Collect up all fields that were significantly changed
|
if diff_fields.is_empty() {
|
||||||
// i.e., those that contain T in coerce_unsized T -> U
|
struct_span_err!(
|
||||||
Some((i, a, b))
|
tcx.sess,
|
||||||
})
|
span,
|
||||||
.collect::<Vec<_>>();
|
E0374,
|
||||||
|
"the trait `CoerceUnsized` may only be implemented \
|
||||||
if diff_fields.is_empty() {
|
for a coercion between structures with one field \
|
||||||
struct_span_err!(
|
being coerced, none found"
|
||||||
tcx.sess,
|
)
|
||||||
span,
|
.emit();
|
||||||
E0374,
|
return err_info;
|
||||||
"the trait `CoerceUnsized` may only be implemented \
|
} else if diff_fields.len() > 1 {
|
||||||
for a coercion between structures with one field \
|
let item = tcx.hir().expect_item(impl_did);
|
||||||
being coerced, none found"
|
let span =
|
||||||
)
|
if let ItemKind::Impl(hir::Impl { of_trait: Some(ref t), .. }) = item.kind {
|
||||||
.emit();
|
|
||||||
return err_info;
|
|
||||||
} else if diff_fields.len() > 1 {
|
|
||||||
let item = tcx.hir().expect_item(impl_did);
|
|
||||||
let span = if let ItemKind::Impl(hir::Impl { of_trait: Some(ref t), .. }) =
|
|
||||||
item.kind
|
|
||||||
{
|
|
||||||
t.path.span
|
t.path.span
|
||||||
} else {
|
} else {
|
||||||
tcx.def_span(impl_did)
|
tcx.def_span(impl_did)
|
||||||
};
|
};
|
||||||
|
|
||||||
struct_span_err!(
|
|
||||||
tcx.sess,
|
|
||||||
span,
|
|
||||||
E0375,
|
|
||||||
"implementing the trait \
|
|
||||||
`CoerceUnsized` requires multiple \
|
|
||||||
coercions"
|
|
||||||
)
|
|
||||||
.note(
|
|
||||||
"`CoerceUnsized` may only be implemented for \
|
|
||||||
a coercion between structures with one field being coerced",
|
|
||||||
)
|
|
||||||
.note(&format!(
|
|
||||||
"currently, {} fields need coercions: {}",
|
|
||||||
diff_fields.len(),
|
|
||||||
diff_fields
|
|
||||||
.iter()
|
|
||||||
.map(|&(i, a, b)| {
|
|
||||||
format!("`{}` (`{}` to `{}`)", fields[i].name, a, b)
|
|
||||||
})
|
|
||||||
.collect::<Vec<_>>()
|
|
||||||
.join(", ")
|
|
||||||
))
|
|
||||||
.span_label(span, "requires multiple coercions")
|
|
||||||
.emit();
|
|
||||||
return err_info;
|
|
||||||
}
|
|
||||||
|
|
||||||
let (i, a, b) = diff_fields[0];
|
|
||||||
let kind = ty::adjustment::CustomCoerceUnsized::Struct(i);
|
|
||||||
(a, b, coerce_unsized_trait, Some(kind))
|
|
||||||
}
|
|
||||||
|
|
||||||
_ => {
|
|
||||||
struct_span_err!(
|
struct_span_err!(
|
||||||
tcx.sess,
|
tcx.sess,
|
||||||
span,
|
span,
|
||||||
E0376,
|
E0375,
|
||||||
"the trait `CoerceUnsized` may only be implemented \
|
"implementing the trait \
|
||||||
for a coercion between structures"
|
`CoerceUnsized` requires multiple \
|
||||||
|
coercions"
|
||||||
)
|
)
|
||||||
|
.note(
|
||||||
|
"`CoerceUnsized` may only be implemented for \
|
||||||
|
a coercion between structures with one field being coerced",
|
||||||
|
)
|
||||||
|
.note(&format!(
|
||||||
|
"currently, {} fields need coercions: {}",
|
||||||
|
diff_fields.len(),
|
||||||
|
diff_fields
|
||||||
|
.iter()
|
||||||
|
.map(|&(i, a, b)| { format!("`{}` (`{}` to `{}`)", fields[i].name, a, b) })
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
.join(", ")
|
||||||
|
))
|
||||||
|
.span_label(span, "requires multiple coercions")
|
||||||
.emit();
|
.emit();
|
||||||
return err_info;
|
return err_info;
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
// Register an obligation for `A: Trait<B>`.
|
let (i, a, b) = diff_fields[0];
|
||||||
let cause = traits::ObligationCause::misc(span, impl_hir_id);
|
let kind = ty::adjustment::CustomCoerceUnsized::Struct(i);
|
||||||
let predicate = predicate_for_trait_def(
|
(a, b, coerce_unsized_trait, Some(kind))
|
||||||
tcx,
|
|
||||||
param_env,
|
|
||||||
cause,
|
|
||||||
trait_def_id,
|
|
||||||
0,
|
|
||||||
source,
|
|
||||||
&[target.into()],
|
|
||||||
);
|
|
||||||
let errors = traits::fully_solve_obligation(&infcx, predicate);
|
|
||||||
if !errors.is_empty() {
|
|
||||||
infcx.err_ctxt().report_fulfillment_errors(&errors, None, false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Finally, resolve all regions.
|
_ => {
|
||||||
let outlives_env = OutlivesEnvironment::new(param_env);
|
struct_span_err!(
|
||||||
infcx.check_region_obligations_and_report_errors(impl_did, &outlives_env);
|
tcx.sess,
|
||||||
|
span,
|
||||||
|
E0376,
|
||||||
|
"the trait `CoerceUnsized` may only be implemented \
|
||||||
|
for a coercion between structures"
|
||||||
|
)
|
||||||
|
.emit();
|
||||||
|
return err_info;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
CoerceUnsizedInfo { custom_kind: kind }
|
// Register an obligation for `A: Trait<B>`.
|
||||||
})
|
let cause = traits::ObligationCause::misc(span, impl_hir_id);
|
||||||
|
let predicate =
|
||||||
|
predicate_for_trait_def(tcx, param_env, cause, trait_def_id, 0, source, &[target.into()]);
|
||||||
|
let errors = traits::fully_solve_obligation(&infcx, predicate);
|
||||||
|
if !errors.is_empty() {
|
||||||
|
infcx.err_ctxt().report_fulfillment_errors(&errors, None, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Finally, resolve all regions.
|
||||||
|
let outlives_env = OutlivesEnvironment::new(param_env);
|
||||||
|
infcx.check_region_obligations_and_report_errors(impl_did, &outlives_env);
|
||||||
|
|
||||||
|
CoerceUnsizedInfo { custom_kind: kind }
|
||||||
}
|
}
|
||||||
|
|
|
@ -64,38 +64,36 @@ fn diagnostic_hir_wf_check<'tcx>(
|
||||||
|
|
||||||
impl<'tcx> Visitor<'tcx> for HirWfCheck<'tcx> {
|
impl<'tcx> Visitor<'tcx> for HirWfCheck<'tcx> {
|
||||||
fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx>) {
|
fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx>) {
|
||||||
self.tcx.infer_ctxt().enter(|infcx| {
|
let infcx = self.tcx.infer_ctxt().build();
|
||||||
let tcx_ty =
|
let tcx_ty = self.icx.to_ty(ty).fold_with(&mut EraseAllBoundRegions { tcx: self.tcx });
|
||||||
self.icx.to_ty(ty).fold_with(&mut EraseAllBoundRegions { tcx: self.tcx });
|
let cause = traits::ObligationCause::new(
|
||||||
let cause = traits::ObligationCause::new(
|
ty.span,
|
||||||
ty.span,
|
self.hir_id,
|
||||||
self.hir_id,
|
traits::ObligationCauseCode::WellFormed(None),
|
||||||
traits::ObligationCauseCode::WellFormed(None),
|
);
|
||||||
);
|
let errors = traits::fully_solve_obligation(
|
||||||
let errors = traits::fully_solve_obligation(
|
&infcx,
|
||||||
&infcx,
|
traits::Obligation::new(
|
||||||
traits::Obligation::new(
|
cause,
|
||||||
cause,
|
self.param_env,
|
||||||
self.param_env,
|
ty::Binder::dummy(ty::PredicateKind::WellFormed(tcx_ty.into()))
|
||||||
ty::Binder::dummy(ty::PredicateKind::WellFormed(tcx_ty.into()))
|
.to_predicate(self.tcx),
|
||||||
.to_predicate(self.tcx),
|
),
|
||||||
),
|
);
|
||||||
);
|
if !errors.is_empty() {
|
||||||
if !errors.is_empty() {
|
debug!("Wf-check got errors for {:?}: {:?}", ty, errors);
|
||||||
debug!("Wf-check got errors for {:?}: {:?}", ty, errors);
|
for error in errors {
|
||||||
for error in errors {
|
if error.obligation.predicate == self.predicate {
|
||||||
if error.obligation.predicate == self.predicate {
|
// Save the cause from the greatest depth - this corresponds
|
||||||
// Save the cause from the greatest depth - this corresponds
|
// to picking more-specific types (e.g. `MyStruct<u8>`)
|
||||||
// to picking more-specific types (e.g. `MyStruct<u8>`)
|
// over less-specific types (e.g. `Option<MyStruct<u8>>`)
|
||||||
// over less-specific types (e.g. `Option<MyStruct<u8>>`)
|
if self.depth >= self.cause_depth {
|
||||||
if self.depth >= self.cause_depth {
|
self.cause = Some(error.obligation.cause);
|
||||||
self.cause = Some(error.obligation.cause);
|
self.cause_depth = self.depth
|
||||||
self.cause_depth = self.depth
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
self.depth += 1;
|
self.depth += 1;
|
||||||
intravisit::walk_ty(self, ty);
|
intravisit::walk_ty(self, ty);
|
||||||
self.depth -= 1;
|
self.depth -= 1;
|
||||||
|
|
|
@ -139,34 +139,33 @@ fn get_impl_substs<'tcx>(
|
||||||
impl1_def_id: LocalDefId,
|
impl1_def_id: LocalDefId,
|
||||||
impl2_node: Node,
|
impl2_node: Node,
|
||||||
) -> Option<(SubstsRef<'tcx>, SubstsRef<'tcx>)> {
|
) -> Option<(SubstsRef<'tcx>, SubstsRef<'tcx>)> {
|
||||||
tcx.infer_ctxt().enter(|ref infcx| {
|
let infcx = &tcx.infer_ctxt().build();
|
||||||
let ocx = ObligationCtxt::new(infcx);
|
let ocx = ObligationCtxt::new(infcx);
|
||||||
let param_env = tcx.param_env(impl1_def_id);
|
let param_env = tcx.param_env(impl1_def_id);
|
||||||
let impl1_hir_id = tcx.hir().local_def_id_to_hir_id(impl1_def_id);
|
let impl1_hir_id = tcx.hir().local_def_id_to_hir_id(impl1_def_id);
|
||||||
|
|
||||||
let assumed_wf_types =
|
let assumed_wf_types =
|
||||||
ocx.assumed_wf_types(param_env, tcx.def_span(impl1_def_id), impl1_def_id);
|
ocx.assumed_wf_types(param_env, tcx.def_span(impl1_def_id), impl1_def_id);
|
||||||
|
|
||||||
let impl1_substs = InternalSubsts::identity_for_item(tcx, impl1_def_id.to_def_id());
|
let impl1_substs = InternalSubsts::identity_for_item(tcx, impl1_def_id.to_def_id());
|
||||||
let impl2_substs =
|
let impl2_substs =
|
||||||
translate_substs(infcx, param_env, impl1_def_id.to_def_id(), impl1_substs, impl2_node);
|
translate_substs(infcx, param_env, impl1_def_id.to_def_id(), impl1_substs, impl2_node);
|
||||||
|
|
||||||
let errors = ocx.select_all_or_error();
|
let errors = ocx.select_all_or_error();
|
||||||
if !errors.is_empty() {
|
if !errors.is_empty() {
|
||||||
ocx.infcx.err_ctxt().report_fulfillment_errors(&errors, None, false);
|
ocx.infcx.err_ctxt().report_fulfillment_errors(&errors, None, false);
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
let implied_bounds = infcx.implied_bounds_tys(param_env, impl1_hir_id, assumed_wf_types);
|
let implied_bounds = infcx.implied_bounds_tys(param_env, impl1_hir_id, assumed_wf_types);
|
||||||
let outlives_env = OutlivesEnvironment::with_bounds(param_env, Some(infcx), implied_bounds);
|
let outlives_env = OutlivesEnvironment::with_bounds(param_env, Some(infcx), implied_bounds);
|
||||||
infcx.check_region_obligations_and_report_errors(impl1_def_id, &outlives_env);
|
infcx.check_region_obligations_and_report_errors(impl1_def_id, &outlives_env);
|
||||||
let Ok(impl2_substs) = infcx.fully_resolve(impl2_substs) else {
|
let Ok(impl2_substs) = infcx.fully_resolve(impl2_substs) else {
|
||||||
let span = tcx.def_span(impl1_def_id);
|
let span = tcx.def_span(impl1_def_id);
|
||||||
tcx.sess.emit_err(SubstsOnOverriddenImpl { span });
|
tcx.sess.emit_err(SubstsOnOverriddenImpl { span });
|
||||||
return None;
|
return None;
|
||||||
};
|
};
|
||||||
Some((impl1_substs, impl2_substs))
|
Some((impl1_substs, impl2_substs))
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a list of all of the unconstrained subst of the given impl.
|
/// Returns a list of all of the unconstrained subst of the given impl.
|
||||||
|
@ -344,23 +343,21 @@ fn check_predicates<'tcx>(
|
||||||
|
|
||||||
// Include the well-formed predicates of the type parameters of the impl.
|
// Include the well-formed predicates of the type parameters of the impl.
|
||||||
for arg in tcx.impl_trait_ref(impl1_def_id).unwrap().substs {
|
for arg in tcx.impl_trait_ref(impl1_def_id).unwrap().substs {
|
||||||
tcx.infer_ctxt().enter(|ref infcx| {
|
let infcx = &tcx.infer_ctxt().build();
|
||||||
let obligations = wf::obligations(
|
let obligations = wf::obligations(
|
||||||
infcx,
|
infcx,
|
||||||
tcx.param_env(impl1_def_id),
|
tcx.param_env(impl1_def_id),
|
||||||
tcx.hir().local_def_id_to_hir_id(impl1_def_id),
|
tcx.hir().local_def_id_to_hir_id(impl1_def_id),
|
||||||
0,
|
0,
|
||||||
arg,
|
arg,
|
||||||
span,
|
span,
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
assert!(!obligations.needs_infer());
|
assert!(!obligations.needs_infer());
|
||||||
impl2_predicates.extend(
|
impl2_predicates.extend(
|
||||||
traits::elaborate_obligations(tcx, obligations)
|
traits::elaborate_obligations(tcx, obligations).map(|obligation| obligation.predicate),
|
||||||
.map(|obligation| obligation.predicate),
|
)
|
||||||
)
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
impl2_predicates.extend(
|
impl2_predicates.extend(
|
||||||
traits::elaborate_predicates_with_span(tcx, always_applicable_traits)
|
traits::elaborate_predicates_with_span(tcx, always_applicable_traits)
|
||||||
|
|
|
@ -141,24 +141,23 @@ fn require_same_types<'tcx>(
|
||||||
expected: Ty<'tcx>,
|
expected: Ty<'tcx>,
|
||||||
actual: Ty<'tcx>,
|
actual: Ty<'tcx>,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
tcx.infer_ctxt().enter(|ref infcx| {
|
let infcx = &tcx.infer_ctxt().build();
|
||||||
let param_env = ty::ParamEnv::empty();
|
let param_env = ty::ParamEnv::empty();
|
||||||
let errors = match infcx.at(cause, param_env).eq(expected, actual) {
|
let errors = match infcx.at(cause, param_env).eq(expected, actual) {
|
||||||
Ok(InferOk { obligations, .. }) => traits::fully_solve_obligations(infcx, obligations),
|
Ok(InferOk { obligations, .. }) => traits::fully_solve_obligations(infcx, obligations),
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
infcx.err_ctxt().report_mismatched_types(cause, expected, actual, err).emit();
|
infcx.err_ctxt().report_mismatched_types(cause, expected, actual, err).emit();
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
match &errors[..] {
|
|
||||||
[] => true,
|
|
||||||
errors => {
|
|
||||||
infcx.err_ctxt().report_fulfillment_errors(errors, None, false);
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
})
|
};
|
||||||
|
|
||||||
|
match &errors[..] {
|
||||||
|
[] => true,
|
||||||
|
errors => {
|
||||||
|
infcx.err_ctxt().report_fulfillment_errors(errors, None, false);
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_main_fn_ty(tcx: TyCtxt<'_>, main_def_id: DefId) {
|
fn check_main_fn_ty(tcx: TyCtxt<'_>, main_def_id: DefId) {
|
||||||
|
@ -305,23 +304,22 @@ fn check_main_fn_ty(tcx: TyCtxt<'_>, main_def_id: DefId) {
|
||||||
error = true;
|
error = true;
|
||||||
}
|
}
|
||||||
let return_ty = return_ty.skip_binder();
|
let return_ty = return_ty.skip_binder();
|
||||||
tcx.infer_ctxt().enter(|infcx| {
|
let infcx = tcx.infer_ctxt().build();
|
||||||
// Main should have no WC, so empty param env is OK here.
|
// Main should have no WC, so empty param env is OK here.
|
||||||
let param_env = ty::ParamEnv::empty();
|
let param_env = ty::ParamEnv::empty();
|
||||||
let cause = traits::ObligationCause::new(
|
let cause = traits::ObligationCause::new(
|
||||||
return_ty_span,
|
return_ty_span,
|
||||||
main_diagnostics_hir_id,
|
main_diagnostics_hir_id,
|
||||||
ObligationCauseCode::MainFunctionType,
|
ObligationCauseCode::MainFunctionType,
|
||||||
);
|
);
|
||||||
let ocx = traits::ObligationCtxt::new(&infcx);
|
let ocx = traits::ObligationCtxt::new(&infcx);
|
||||||
let norm_return_ty = ocx.normalize(cause.clone(), param_env, return_ty);
|
let norm_return_ty = ocx.normalize(cause.clone(), param_env, return_ty);
|
||||||
ocx.register_bound(cause, param_env, norm_return_ty, term_did);
|
ocx.register_bound(cause, param_env, norm_return_ty, term_did);
|
||||||
let errors = ocx.select_all_or_error();
|
let errors = ocx.select_all_or_error();
|
||||||
if !errors.is_empty() {
|
if !errors.is_empty() {
|
||||||
infcx.err_ctxt().report_fulfillment_errors(&errors, None, false);
|
infcx.err_ctxt().report_fulfillment_errors(&errors, None, false);
|
||||||
error = true;
|
error = true;
|
||||||
}
|
}
|
||||||
});
|
|
||||||
// now we can take the return type of the given main function
|
// now we can take the return type of the given main function
|
||||||
expected_return_type = main_fnsig.output();
|
expected_return_type = main_fnsig.output();
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -602,30 +602,27 @@ impl<'tcx> InferCtxtBuilder<'tcx> {
|
||||||
/// `V` and a substitution `S`. This substitution `S` maps from
|
/// `V` and a substitution `S`. This substitution `S` maps from
|
||||||
/// the bound values in `C` to their instantiated values in `V`
|
/// the bound values in `C` to their instantiated values in `V`
|
||||||
/// (in other words, `S(C) = V`).
|
/// (in other words, `S(C) = V`).
|
||||||
pub fn enter_with_canonical<T, R>(
|
pub fn build_with_canonical<T>(
|
||||||
&mut self,
|
&mut self,
|
||||||
span: Span,
|
span: Span,
|
||||||
canonical: &Canonical<'tcx, T>,
|
canonical: &Canonical<'tcx, T>,
|
||||||
f: impl FnOnce(InferCtxt<'tcx>, T, CanonicalVarValues<'tcx>) -> R,
|
) -> (InferCtxt<'tcx>, T, CanonicalVarValues<'tcx>)
|
||||||
) -> R
|
|
||||||
where
|
where
|
||||||
T: TypeFoldable<'tcx>,
|
T: TypeFoldable<'tcx>,
|
||||||
{
|
{
|
||||||
self.enter(|infcx| {
|
let infcx = self.build();
|
||||||
let (value, subst) =
|
let (value, subst) = infcx.instantiate_canonical_with_fresh_inference_vars(span, canonical);
|
||||||
infcx.instantiate_canonical_with_fresh_inference_vars(span, canonical);
|
(infcx, value, subst)
|
||||||
f(infcx, value, subst)
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn enter<R>(&mut self, f: impl FnOnce(InferCtxt<'tcx>) -> R) -> R {
|
pub fn build(&mut self) -> InferCtxt<'tcx> {
|
||||||
let InferCtxtBuilder {
|
let InferCtxtBuilder {
|
||||||
tcx,
|
tcx,
|
||||||
defining_use_anchor,
|
defining_use_anchor,
|
||||||
considering_regions,
|
considering_regions,
|
||||||
ref normalize_fn_sig_for_diagnostic,
|
ref normalize_fn_sig_for_diagnostic,
|
||||||
} = *self;
|
} = *self;
|
||||||
f(InferCtxt {
|
InferCtxt {
|
||||||
tcx,
|
tcx,
|
||||||
defining_use_anchor,
|
defining_use_anchor,
|
||||||
considering_regions,
|
considering_regions,
|
||||||
|
@ -643,7 +640,7 @@ impl<'tcx> InferCtxtBuilder<'tcx> {
|
||||||
normalize_fn_sig_for_diagnostic: normalize_fn_sig_for_diagnostic
|
normalize_fn_sig_for_diagnostic: normalize_fn_sig_for_diagnostic
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.map(|f| f.clone()),
|
.map(|f| f.clone()),
|
||||||
})
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -151,21 +151,19 @@ fn check_panic<'tcx>(cx: &LateContext<'tcx>, f: &'tcx hir::Expr<'tcx>, arg: &'tc
|
||||||
Some(ty_def) if cx.tcx.is_diagnostic_item(sym::String, ty_def.did()),
|
Some(ty_def) if cx.tcx.is_diagnostic_item(sym::String, ty_def.did()),
|
||||||
);
|
);
|
||||||
|
|
||||||
let (suggest_display, suggest_debug) = cx.tcx.infer_ctxt().enter(|infcx| {
|
let infcx = cx.tcx.infer_ctxt().build();
|
||||||
let display = is_str
|
let suggest_display = is_str
|
||||||
|| cx.tcx.get_diagnostic_item(sym::Display).map(|t| {
|
|| cx.tcx.get_diagnostic_item(sym::Display).map(|t| {
|
||||||
infcx
|
infcx
|
||||||
.type_implements_trait(t, ty, InternalSubsts::empty(), cx.param_env)
|
.type_implements_trait(t, ty, InternalSubsts::empty(), cx.param_env)
|
||||||
.may_apply()
|
.may_apply()
|
||||||
}) == Some(true);
|
}) == Some(true);
|
||||||
let debug = !display
|
let suggest_debug = !suggest_display
|
||||||
&& cx.tcx.get_diagnostic_item(sym::Debug).map(|t| {
|
&& cx.tcx.get_diagnostic_item(sym::Debug).map(|t| {
|
||||||
infcx
|
infcx
|
||||||
.type_implements_trait(t, ty, InternalSubsts::empty(), cx.param_env)
|
.type_implements_trait(t, ty, InternalSubsts::empty(), cx.param_env)
|
||||||
.may_apply()
|
.may_apply()
|
||||||
}) == Some(true);
|
}) == Some(true);
|
||||||
(display, debug)
|
|
||||||
});
|
|
||||||
|
|
||||||
let suggest_panic_any = !is_str && panic == sym::std_panic_macro;
|
let suggest_panic_any = !is_str && panic == sym::std_panic_macro;
|
||||||
|
|
||||||
|
|
|
@ -62,85 +62,81 @@ impl<'tcx> LateLintPass<'tcx> for OpaqueHiddenInferredBound {
|
||||||
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'tcx>) {
|
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'tcx>) {
|
||||||
let hir::ItemKind::OpaqueTy(_) = &item.kind else { return; };
|
let hir::ItemKind::OpaqueTy(_) = &item.kind else { return; };
|
||||||
let def_id = item.def_id.def_id.to_def_id();
|
let def_id = item.def_id.def_id.to_def_id();
|
||||||
cx.tcx.infer_ctxt().enter(|ref infcx| {
|
let infcx = &cx.tcx.infer_ctxt().build();
|
||||||
// For every projection predicate in the opaque type's explicit bounds,
|
// For every projection predicate in the opaque type's explicit bounds,
|
||||||
// check that the type that we're assigning actually satisfies the bounds
|
// check that the type that we're assigning actually satisfies the bounds
|
||||||
// of the associated type.
|
// of the associated type.
|
||||||
for &(pred, pred_span) in cx.tcx.explicit_item_bounds(def_id) {
|
for &(pred, pred_span) in cx.tcx.explicit_item_bounds(def_id) {
|
||||||
// Liberate bound regions in the predicate since we
|
// Liberate bound regions in the predicate since we
|
||||||
// don't actually care about lifetimes in this check.
|
// don't actually care about lifetimes in this check.
|
||||||
let predicate = cx.tcx.liberate_late_bound_regions(
|
let predicate = cx.tcx.liberate_late_bound_regions(def_id, pred.kind());
|
||||||
def_id,
|
let ty::PredicateKind::Projection(proj) = predicate else {
|
||||||
pred.kind(),
|
continue;
|
||||||
);
|
};
|
||||||
let ty::PredicateKind::Projection(proj) = predicate else {
|
// Only check types, since those are the only things that may
|
||||||
|
// have opaques in them anyways.
|
||||||
|
let Some(proj_term) = proj.term.ty() else { continue };
|
||||||
|
|
||||||
|
let proj_ty =
|
||||||
|
cx.tcx.mk_projection(proj.projection_ty.item_def_id, proj.projection_ty.substs);
|
||||||
|
// For every instance of the projection type in the bounds,
|
||||||
|
// replace them with the term we're assigning to the associated
|
||||||
|
// type in our opaque type.
|
||||||
|
let proj_replacer = &mut BottomUpFolder {
|
||||||
|
tcx: cx.tcx,
|
||||||
|
ty_op: |ty| if ty == proj_ty { proj_term } else { ty },
|
||||||
|
lt_op: |lt| lt,
|
||||||
|
ct_op: |ct| ct,
|
||||||
|
};
|
||||||
|
// For example, in `impl Trait<Assoc = impl Send>`, for all of the bounds on `Assoc`,
|
||||||
|
// e.g. `type Assoc: OtherTrait`, replace `<impl Trait as Trait>::Assoc: OtherTrait`
|
||||||
|
// with `impl Send: OtherTrait`.
|
||||||
|
for assoc_pred_and_span in
|
||||||
|
cx.tcx.bound_explicit_item_bounds(proj.projection_ty.item_def_id).transpose_iter()
|
||||||
|
{
|
||||||
|
let assoc_pred_span = assoc_pred_and_span.0.1;
|
||||||
|
let assoc_pred = assoc_pred_and_span
|
||||||
|
.map_bound(|(pred, _)| *pred)
|
||||||
|
.subst(cx.tcx, &proj.projection_ty.substs)
|
||||||
|
.fold_with(proj_replacer);
|
||||||
|
let Ok(assoc_pred) = traits::fully_normalize(infcx, traits::ObligationCause::dummy(), cx.param_env, assoc_pred) else {
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
// Only check types, since those are the only things that may
|
// If that predicate doesn't hold modulo regions (but passed during type-check),
|
||||||
// have opaques in them anyways.
|
// then we must've taken advantage of the hack in `project_and_unify_types` where
|
||||||
let Some(proj_term) = proj.term.ty() else { continue };
|
// we replace opaques with inference vars. Emit a warning!
|
||||||
|
if !infcx.predicate_must_hold_modulo_regions(&traits::Obligation::new(
|
||||||
let proj_ty =
|
traits::ObligationCause::dummy(),
|
||||||
cx
|
cx.param_env,
|
||||||
.tcx
|
assoc_pred,
|
||||||
.mk_projection(proj.projection_ty.item_def_id, proj.projection_ty.substs);
|
)) {
|
||||||
// For every instance of the projection type in the bounds,
|
// If it's a trait bound and an opaque that doesn't satisfy it,
|
||||||
// replace them with the term we're assigning to the associated
|
// then we can emit a suggestion to add the bound.
|
||||||
// type in our opaque type.
|
let add_bound = match (proj_term.kind(), assoc_pred.kind().skip_binder()) {
|
||||||
let proj_replacer = &mut BottomUpFolder {
|
(ty::Opaque(def_id, _), ty::PredicateKind::Trait(trait_pred)) => {
|
||||||
tcx: cx.tcx,
|
Some(AddBound {
|
||||||
ty_op: |ty| if ty == proj_ty { proj_term } else { ty },
|
suggest_span: cx.tcx.def_span(*def_id).shrink_to_hi(),
|
||||||
lt_op: |lt| lt,
|
trait_ref: trait_pred.print_modifiers_and_trait_path(),
|
||||||
ct_op: |ct| ct,
|
})
|
||||||
};
|
}
|
||||||
// For example, in `impl Trait<Assoc = impl Send>`, for all of the bounds on `Assoc`,
|
_ => None,
|
||||||
// e.g. `type Assoc: OtherTrait`, replace `<impl Trait as Trait>::Assoc: OtherTrait`
|
|
||||||
// with `impl Send: OtherTrait`.
|
|
||||||
for assoc_pred_and_span in cx
|
|
||||||
.tcx
|
|
||||||
.bound_explicit_item_bounds(proj.projection_ty.item_def_id)
|
|
||||||
.transpose_iter()
|
|
||||||
{
|
|
||||||
let assoc_pred_span = assoc_pred_and_span.0.1;
|
|
||||||
let assoc_pred = assoc_pred_and_span
|
|
||||||
.map_bound(|(pred, _)| *pred)
|
|
||||||
.subst(cx.tcx, &proj.projection_ty.substs)
|
|
||||||
.fold_with(proj_replacer);
|
|
||||||
let Ok(assoc_pred) = traits::fully_normalize(infcx, traits::ObligationCause::dummy(), cx.param_env, assoc_pred) else {
|
|
||||||
continue;
|
|
||||||
};
|
};
|
||||||
// If that predicate doesn't hold modulo regions (but passed during type-check),
|
cx.emit_spanned_lint(
|
||||||
// then we must've taken advantage of the hack in `project_and_unify_types` where
|
OPAQUE_HIDDEN_INFERRED_BOUND,
|
||||||
// we replace opaques with inference vars. Emit a warning!
|
pred_span,
|
||||||
if !infcx.predicate_must_hold_modulo_regions(&traits::Obligation::new(
|
OpaqueHiddenInferredBoundLint {
|
||||||
traits::ObligationCause::dummy(),
|
ty: cx.tcx.mk_opaque(
|
||||||
cx.param_env,
|
def_id,
|
||||||
assoc_pred,
|
ty::InternalSubsts::identity_for_item(cx.tcx, def_id),
|
||||||
)) {
|
),
|
||||||
// If it's a trait bound and an opaque that doesn't satisfy it,
|
proj_ty: proj_term,
|
||||||
// then we can emit a suggestion to add the bound.
|
assoc_pred_span,
|
||||||
let add_bound =
|
add_bound,
|
||||||
match (proj_term.kind(), assoc_pred.kind().skip_binder()) {
|
},
|
||||||
(ty::Opaque(def_id, _), ty::PredicateKind::Trait(trait_pred)) => Some(AddBound {
|
);
|
||||||
suggest_span: cx.tcx.def_span(*def_id).shrink_to_hi(),
|
|
||||||
trait_ref: trait_pred.print_modifiers_and_trait_path(),
|
|
||||||
}),
|
|
||||||
_ => None,
|
|
||||||
};
|
|
||||||
cx.emit_spanned_lint(
|
|
||||||
OPAQUE_HIDDEN_INFERRED_BOUND,
|
|
||||||
pred_span,
|
|
||||||
OpaqueHiddenInferredBoundLint {
|
|
||||||
ty: cx.tcx.mk_opaque(def_id, ty::InternalSubsts::identity_for_item(cx.tcx, def_id)),
|
|
||||||
proj_ty: proj_term,
|
|
||||||
assoc_pred_span,
|
|
||||||
add_bound,
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -481,54 +481,49 @@ fn construct_fn<'tcx>(
|
||||||
(None, fn_sig.output())
|
(None, fn_sig.output())
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut body = tcx.infer_ctxt().enter(|infcx| {
|
let infcx = tcx.infer_ctxt().build();
|
||||||
let mut builder = Builder::new(
|
let mut builder = Builder::new(
|
||||||
thir,
|
thir,
|
||||||
infcx,
|
infcx,
|
||||||
fn_def,
|
fn_def,
|
||||||
fn_id,
|
fn_id,
|
||||||
span_with_body,
|
span_with_body,
|
||||||
arguments.len(),
|
arguments.len(),
|
||||||
safety,
|
safety,
|
||||||
return_ty,
|
return_ty,
|
||||||
return_ty_span,
|
return_ty_span,
|
||||||
generator_kind,
|
generator_kind,
|
||||||
);
|
);
|
||||||
|
|
||||||
let call_site_scope =
|
let call_site_scope =
|
||||||
region::Scope { id: body_id.hir_id.local_id, data: region::ScopeData::CallSite };
|
region::Scope { id: body_id.hir_id.local_id, data: region::ScopeData::CallSite };
|
||||||
let arg_scope =
|
let arg_scope =
|
||||||
region::Scope { id: body_id.hir_id.local_id, data: region::ScopeData::Arguments };
|
region::Scope { id: body_id.hir_id.local_id, data: region::ScopeData::Arguments };
|
||||||
let source_info = builder.source_info(span);
|
let source_info = builder.source_info(span);
|
||||||
let call_site_s = (call_site_scope, source_info);
|
let call_site_s = (call_site_scope, source_info);
|
||||||
unpack!(builder.in_scope(call_site_s, LintLevel::Inherited, |builder| {
|
unpack!(builder.in_scope(call_site_s, LintLevel::Inherited, |builder| {
|
||||||
let arg_scope_s = (arg_scope, source_info);
|
let arg_scope_s = (arg_scope, source_info);
|
||||||
// Attribute epilogue to function's closing brace
|
// Attribute epilogue to function's closing brace
|
||||||
let fn_end = span_with_body.shrink_to_hi();
|
let fn_end = span_with_body.shrink_to_hi();
|
||||||
let return_block = unpack!(builder.in_breakable_scope(
|
let return_block =
|
||||||
None,
|
unpack!(builder.in_breakable_scope(None, Place::return_place(), fn_end, |builder| {
|
||||||
Place::return_place(),
|
Some(builder.in_scope(arg_scope_s, LintLevel::Inherited, |builder| {
|
||||||
fn_end,
|
builder.args_and_body(
|
||||||
|builder| {
|
START_BLOCK,
|
||||||
Some(builder.in_scope(arg_scope_s, LintLevel::Inherited, |builder| {
|
fn_def.did,
|
||||||
builder.args_and_body(
|
arguments,
|
||||||
START_BLOCK,
|
arg_scope,
|
||||||
fn_def.did,
|
&thir[expr],
|
||||||
arguments,
|
)
|
||||||
arg_scope,
|
}))
|
||||||
&thir[expr],
|
}));
|
||||||
)
|
let source_info = builder.source_info(fn_end);
|
||||||
}))
|
builder.cfg.terminate(return_block, source_info, TerminatorKind::Return);
|
||||||
}
|
builder.build_drop_trees();
|
||||||
));
|
return_block.unit()
|
||||||
let source_info = builder.source_info(fn_end);
|
}));
|
||||||
builder.cfg.terminate(return_block, source_info, TerminatorKind::Return);
|
|
||||||
builder.build_drop_trees();
|
|
||||||
return_block.unit()
|
|
||||||
}));
|
|
||||||
|
|
||||||
builder.finish()
|
let mut body = builder.finish();
|
||||||
});
|
|
||||||
|
|
||||||
body.spread_arg = if abi == Abi::RustCall {
|
body.spread_arg = if abi == Abi::RustCall {
|
||||||
// RustCall pseudo-ABI untuples the last argument.
|
// RustCall pseudo-ABI untuples the last argument.
|
||||||
|
@ -584,30 +579,29 @@ fn construct_const<'a, 'tcx>(
|
||||||
let typeck_results = tcx.typeck_opt_const_arg(def);
|
let typeck_results = tcx.typeck_opt_const_arg(def);
|
||||||
let const_ty = typeck_results.node_type(hir_id);
|
let const_ty = typeck_results.node_type(hir_id);
|
||||||
|
|
||||||
tcx.infer_ctxt().enter(|infcx| {
|
let infcx = tcx.infer_ctxt().build();
|
||||||
let mut builder = Builder::new(
|
let mut builder = Builder::new(
|
||||||
thir,
|
thir,
|
||||||
infcx,
|
infcx,
|
||||||
def,
|
def,
|
||||||
hir_id,
|
hir_id,
|
||||||
span,
|
span,
|
||||||
0,
|
0,
|
||||||
Safety::Safe,
|
Safety::Safe,
|
||||||
const_ty,
|
const_ty,
|
||||||
const_ty_span,
|
const_ty_span,
|
||||||
None,
|
None,
|
||||||
);
|
);
|
||||||
|
|
||||||
let mut block = START_BLOCK;
|
let mut block = START_BLOCK;
|
||||||
unpack!(block = builder.expr_into_dest(Place::return_place(), block, &thir[expr]));
|
unpack!(block = builder.expr_into_dest(Place::return_place(), block, &thir[expr]));
|
||||||
|
|
||||||
let source_info = builder.source_info(span);
|
let source_info = builder.source_info(span);
|
||||||
builder.cfg.terminate(block, source_info, TerminatorKind::Return);
|
builder.cfg.terminate(block, source_info, TerminatorKind::Return);
|
||||||
|
|
||||||
builder.build_drop_trees();
|
builder.build_drop_trees();
|
||||||
|
|
||||||
builder.finish()
|
builder.finish()
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Construct MIR for an item that has had errors in type checking.
|
/// Construct MIR for an item that has had errors in type checking.
|
||||||
|
|
|
@ -28,10 +28,9 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
|
||||||
span: Span,
|
span: Span,
|
||||||
mir_structural_match_violation: bool,
|
mir_structural_match_violation: bool,
|
||||||
) -> Box<Pat<'tcx>> {
|
) -> Box<Pat<'tcx>> {
|
||||||
self.tcx.infer_ctxt().enter(|infcx| {
|
let infcx = self.tcx.infer_ctxt().build();
|
||||||
let mut convert = ConstToPat::new(self, id, span, infcx);
|
let mut convert = ConstToPat::new(self, id, span, infcx);
|
||||||
convert.to_pat(cv, mir_structural_match_violation)
|
convert.to_pat(cv, mir_structural_match_violation)
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -177,18 +177,10 @@ impl<'tcx> InferCtxtBuilderExt<'tcx> for InferCtxtBuilder<'tcx> {
|
||||||
R: Debug + TypeFoldable<'tcx>,
|
R: Debug + TypeFoldable<'tcx>,
|
||||||
Canonical<'tcx, QueryResponse<'tcx, R>>: ArenaAllocatable<'tcx>,
|
Canonical<'tcx, QueryResponse<'tcx, R>>: ArenaAllocatable<'tcx>,
|
||||||
{
|
{
|
||||||
self.enter_with_canonical(
|
let (ref infcx, key, canonical_inference_vars) =
|
||||||
DUMMY_SP,
|
self.build_with_canonical(DUMMY_SP, canonical_key);
|
||||||
canonical_key,
|
let mut fulfill_cx = <dyn TraitEngine<'_>>::new(infcx.tcx);
|
||||||
|ref infcx, key, canonical_inference_vars| {
|
let value = operation(infcx, &mut *fulfill_cx, key)?;
|
||||||
let mut fulfill_cx = <dyn TraitEngine<'_>>::new(infcx.tcx);
|
infcx.make_canonicalized_query_response(canonical_inference_vars, value, &mut *fulfill_cx)
|
||||||
let value = operation(infcx, &mut *fulfill_cx, key)?;
|
|
||||||
infcx.make_canonicalized_query_response(
|
|
||||||
canonical_inference_vars,
|
|
||||||
value,
|
|
||||||
&mut *fulfill_cx,
|
|
||||||
)
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,7 +10,7 @@ use crate::traits::project::ProjectAndUnifyResult;
|
||||||
use rustc_middle::mir::interpret::ErrorHandled;
|
use rustc_middle::mir::interpret::ErrorHandled;
|
||||||
use rustc_middle::ty::fold::{TypeFolder, TypeSuperFoldable};
|
use rustc_middle::ty::fold::{TypeFolder, TypeSuperFoldable};
|
||||||
use rustc_middle::ty::visit::TypeVisitable;
|
use rustc_middle::ty::visit::TypeVisitable;
|
||||||
use rustc_middle::ty::{Region, RegionVid};
|
use rustc_middle::ty::{PolyTraitRef, Region, RegionVid};
|
||||||
|
|
||||||
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
||||||
|
|
||||||
|
@ -90,143 +90,105 @@ impl<'tcx> AutoTraitFinder<'tcx> {
|
||||||
|
|
||||||
let trait_pred = ty::Binder::dummy(trait_ref);
|
let trait_pred = ty::Binder::dummy(trait_ref);
|
||||||
|
|
||||||
let bail_out = tcx.infer_ctxt().enter(|infcx| {
|
let infcx = tcx.infer_ctxt().build();
|
||||||
let mut selcx = SelectionContext::new(&infcx);
|
let mut selcx = SelectionContext::new(&infcx);
|
||||||
let result = selcx.select(&Obligation::new(
|
for f in [
|
||||||
ObligationCause::dummy(),
|
PolyTraitRef::to_poly_trait_predicate,
|
||||||
orig_env,
|
PolyTraitRef::to_poly_trait_predicate_negative_polarity,
|
||||||
trait_pred.to_poly_trait_predicate(),
|
] {
|
||||||
));
|
let result =
|
||||||
|
selcx.select(&Obligation::new(ObligationCause::dummy(), orig_env, f(&trait_pred)));
|
||||||
match result {
|
if let Ok(Some(ImplSource::UserDefined(_))) = result {
|
||||||
Ok(Some(ImplSource::UserDefined(_))) => {
|
debug!(
|
||||||
debug!(
|
"find_auto_trait_generics({:?}): \
|
||||||
"find_auto_trait_generics({:?}): \
|
manual impl found, bailing out",
|
||||||
manual impl found, bailing out",
|
trait_ref
|
||||||
trait_ref
|
);
|
||||||
);
|
// If an explicit impl exists, it always takes priority over an auto impl
|
||||||
return true;
|
return AutoTraitResult::ExplicitImpl;
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let result = selcx.select(&Obligation::new(
|
|
||||||
ObligationCause::dummy(),
|
|
||||||
orig_env,
|
|
||||||
trait_pred.to_poly_trait_predicate_negative_polarity(),
|
|
||||||
));
|
|
||||||
|
|
||||||
match result {
|
|
||||||
Ok(Some(ImplSource::UserDefined(_))) => {
|
|
||||||
debug!(
|
|
||||||
"find_auto_trait_generics({:?}): \
|
|
||||||
manual impl found, bailing out",
|
|
||||||
trait_ref
|
|
||||||
);
|
|
||||||
true
|
|
||||||
}
|
|
||||||
_ => false,
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// If an explicit impl exists, it always takes priority over an auto impl
|
|
||||||
if bail_out {
|
|
||||||
return AutoTraitResult::ExplicitImpl;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
tcx.infer_ctxt().enter(|infcx| {
|
let infcx = tcx.infer_ctxt().build();
|
||||||
let mut fresh_preds = FxHashSet::default();
|
let mut fresh_preds = FxHashSet::default();
|
||||||
|
|
||||||
// Due to the way projections are handled by SelectionContext, we need to run
|
// Due to the way projections are handled by SelectionContext, we need to run
|
||||||
// evaluate_predicates twice: once on the original param env, and once on the result of
|
// evaluate_predicates twice: once on the original param env, and once on the result of
|
||||||
// the first evaluate_predicates call.
|
// the first evaluate_predicates call.
|
||||||
//
|
//
|
||||||
// The problem is this: most of rustc, including SelectionContext and traits::project,
|
// The problem is this: most of rustc, including SelectionContext and traits::project,
|
||||||
// are designed to work with a concrete usage of a type (e.g., Vec<u8>
|
// are designed to work with a concrete usage of a type (e.g., Vec<u8>
|
||||||
// fn<T>() { Vec<T> }. This information will generally never change - given
|
// fn<T>() { Vec<T> }. This information will generally never change - given
|
||||||
// the 'T' in fn<T>() { ... }, we'll never know anything else about 'T'.
|
// the 'T' in fn<T>() { ... }, we'll never know anything else about 'T'.
|
||||||
// If we're unable to prove that 'T' implements a particular trait, we're done -
|
// If we're unable to prove that 'T' implements a particular trait, we're done -
|
||||||
// there's nothing left to do but error out.
|
// there's nothing left to do but error out.
|
||||||
//
|
//
|
||||||
// However, synthesizing an auto trait impl works differently. Here, we start out with
|
// However, synthesizing an auto trait impl works differently. Here, we start out with
|
||||||
// a set of initial conditions - the ParamEnv of the struct/enum/union we're dealing
|
// a set of initial conditions - the ParamEnv of the struct/enum/union we're dealing
|
||||||
// with - and progressively discover the conditions we need to fulfill for it to
|
// with - and progressively discover the conditions we need to fulfill for it to
|
||||||
// implement a certain auto trait. This ends up breaking two assumptions made by trait
|
// implement a certain auto trait. This ends up breaking two assumptions made by trait
|
||||||
// selection and projection:
|
// selection and projection:
|
||||||
//
|
//
|
||||||
// * We can always cache the result of a particular trait selection for the lifetime of
|
// * We can always cache the result of a particular trait selection for the lifetime of
|
||||||
// an InfCtxt
|
// an InfCtxt
|
||||||
// * Given a projection bound such as '<T as SomeTrait>::SomeItem = K', if 'T:
|
// * Given a projection bound such as '<T as SomeTrait>::SomeItem = K', if 'T:
|
||||||
// SomeTrait' doesn't hold, then we don't need to care about the 'SomeItem = K'
|
// SomeTrait' doesn't hold, then we don't need to care about the 'SomeItem = K'
|
||||||
//
|
//
|
||||||
// We fix the first assumption by manually clearing out all of the InferCtxt's caches
|
// We fix the first assumption by manually clearing out all of the InferCtxt's caches
|
||||||
// in between calls to SelectionContext.select. This allows us to keep all of the
|
// in between calls to SelectionContext.select. This allows us to keep all of the
|
||||||
// intermediate types we create bound to the 'tcx lifetime, rather than needing to lift
|
// intermediate types we create bound to the 'tcx lifetime, rather than needing to lift
|
||||||
// them between calls.
|
// them between calls.
|
||||||
//
|
//
|
||||||
// We fix the second assumption by reprocessing the result of our first call to
|
// We fix the second assumption by reprocessing the result of our first call to
|
||||||
// evaluate_predicates. Using the example of '<T as SomeTrait>::SomeItem = K', our first
|
// evaluate_predicates. Using the example of '<T as SomeTrait>::SomeItem = K', our first
|
||||||
// pass will pick up 'T: SomeTrait', but not 'SomeItem = K'. On our second pass,
|
// pass will pick up 'T: SomeTrait', but not 'SomeItem = K'. On our second pass,
|
||||||
// traits::project will see that 'T: SomeTrait' is in our ParamEnv, allowing
|
// traits::project will see that 'T: SomeTrait' is in our ParamEnv, allowing
|
||||||
// SelectionContext to return it back to us.
|
// SelectionContext to return it back to us.
|
||||||
|
|
||||||
let Some((new_env, user_env)) = self.evaluate_predicates(
|
let Some((new_env, user_env)) = self.evaluate_predicates(
|
||||||
&infcx,
|
&infcx,
|
||||||
trait_did,
|
trait_did,
|
||||||
ty,
|
ty,
|
||||||
orig_env,
|
orig_env,
|
||||||
orig_env,
|
orig_env,
|
||||||
&mut fresh_preds,
|
&mut fresh_preds,
|
||||||
false,
|
false,
|
||||||
) else {
|
) else {
|
||||||
return AutoTraitResult::NegativeImpl;
|
return AutoTraitResult::NegativeImpl;
|
||||||
};
|
};
|
||||||
|
|
||||||
let (full_env, full_user_env) = self
|
let (full_env, full_user_env) = self
|
||||||
.evaluate_predicates(
|
.evaluate_predicates(&infcx, trait_did, ty, new_env, user_env, &mut fresh_preds, true)
|
||||||
&infcx,
|
.unwrap_or_else(|| {
|
||||||
trait_did,
|
panic!("Failed to fully process: {:?} {:?} {:?}", ty, trait_did, orig_env)
|
||||||
ty,
|
});
|
||||||
new_env,
|
|
||||||
user_env,
|
|
||||||
&mut fresh_preds,
|
|
||||||
true,
|
|
||||||
)
|
|
||||||
.unwrap_or_else(|| {
|
|
||||||
panic!("Failed to fully process: {:?} {:?} {:?}", ty, trait_did, orig_env)
|
|
||||||
});
|
|
||||||
|
|
||||||
debug!(
|
debug!(
|
||||||
"find_auto_trait_generics({:?}): fulfilling \
|
"find_auto_trait_generics({:?}): fulfilling \
|
||||||
with {:?}",
|
with {:?}",
|
||||||
trait_ref, full_env
|
trait_ref, full_env
|
||||||
);
|
);
|
||||||
infcx.clear_caches();
|
infcx.clear_caches();
|
||||||
|
|
||||||
// At this point, we already have all of the bounds we need. FulfillmentContext is used
|
// At this point, we already have all of the bounds we need. FulfillmentContext is used
|
||||||
// to store all of the necessary region/lifetime bounds in the InferContext, as well as
|
// to store all of the necessary region/lifetime bounds in the InferContext, as well as
|
||||||
// an additional sanity check.
|
// an additional sanity check.
|
||||||
let errors =
|
let errors =
|
||||||
super::fully_solve_bound(&infcx, ObligationCause::dummy(), full_env, ty, trait_did);
|
super::fully_solve_bound(&infcx, ObligationCause::dummy(), full_env, ty, trait_did);
|
||||||
if !errors.is_empty() {
|
if !errors.is_empty() {
|
||||||
panic!("Unable to fulfill trait {:?} for '{:?}': {:?}", trait_did, ty, errors);
|
panic!("Unable to fulfill trait {:?} for '{:?}': {:?}", trait_did, ty, errors);
|
||||||
}
|
}
|
||||||
|
|
||||||
infcx.process_registered_region_obligations(&Default::default(), full_env);
|
infcx.process_registered_region_obligations(&Default::default(), full_env);
|
||||||
|
|
||||||
let region_data = infcx
|
let region_data =
|
||||||
.inner
|
infcx.inner.borrow_mut().unwrap_region_constraints().region_constraint_data().clone();
|
||||||
.borrow_mut()
|
|
||||||
.unwrap_region_constraints()
|
|
||||||
.region_constraint_data()
|
|
||||||
.clone();
|
|
||||||
|
|
||||||
let vid_to_region = self.map_vid_to_region(®ion_data);
|
let vid_to_region = self.map_vid_to_region(®ion_data);
|
||||||
|
|
||||||
let info = AutoTraitInfo { full_user_env, region_data, vid_to_region };
|
let info = AutoTraitInfo { full_user_env, region_data, vid_to_region };
|
||||||
|
|
||||||
AutoTraitResult::PositiveImpl(auto_trait_callback(info))
|
AutoTraitResult::PositiveImpl(auto_trait_callback(info))
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -29,60 +29,61 @@ pub fn codegen_select_candidate<'tcx>(
|
||||||
|
|
||||||
// Do the initial selection for the obligation. This yields the
|
// Do the initial selection for the obligation. This yields the
|
||||||
// shallow result we are looking for -- that is, what specific impl.
|
// shallow result we are looking for -- that is, what specific impl.
|
||||||
let mut infcx_builder =
|
let infcx = tcx
|
||||||
tcx.infer_ctxt().ignoring_regions().with_opaque_type_inference(DefiningAnchor::Bubble);
|
.infer_ctxt()
|
||||||
infcx_builder.enter(|infcx| {
|
.ignoring_regions()
|
||||||
//~^ HACK `Bubble` is required for
|
.with_opaque_type_inference(DefiningAnchor::Bubble)
|
||||||
// this test to pass: type-alias-impl-trait/assoc-projection-ice.rs
|
.build();
|
||||||
let mut selcx = SelectionContext::new(&infcx);
|
//~^ HACK `Bubble` is required for
|
||||||
|
// this test to pass: type-alias-impl-trait/assoc-projection-ice.rs
|
||||||
|
let mut selcx = SelectionContext::new(&infcx);
|
||||||
|
|
||||||
let obligation_cause = ObligationCause::dummy();
|
let obligation_cause = ObligationCause::dummy();
|
||||||
let obligation =
|
let obligation =
|
||||||
Obligation::new(obligation_cause, param_env, trait_ref.to_poly_trait_predicate());
|
Obligation::new(obligation_cause, param_env, trait_ref.to_poly_trait_predicate());
|
||||||
|
|
||||||
let selection = match selcx.select(&obligation) {
|
let selection = match selcx.select(&obligation) {
|
||||||
Ok(Some(selection)) => selection,
|
Ok(Some(selection)) => selection,
|
||||||
Ok(None) => return Err(CodegenObligationError::Ambiguity),
|
Ok(None) => return Err(CodegenObligationError::Ambiguity),
|
||||||
Err(Unimplemented) => return Err(CodegenObligationError::Unimplemented),
|
Err(Unimplemented) => return Err(CodegenObligationError::Unimplemented),
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
bug!("Encountered error `{:?}` selecting `{:?}` during codegen", e, trait_ref)
|
bug!("Encountered error `{:?}` selecting `{:?}` during codegen", e, trait_ref)
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
debug!(?selection);
|
|
||||||
|
|
||||||
// Currently, we use a fulfillment context to completely resolve
|
|
||||||
// all nested obligations. This is because they can inform the
|
|
||||||
// inference of the impl's type parameters.
|
|
||||||
let mut fulfill_cx = <dyn TraitEngine<'tcx>>::new(tcx);
|
|
||||||
let impl_source = selection.map(|predicate| {
|
|
||||||
fulfill_cx.register_predicate_obligation(&infcx, predicate);
|
|
||||||
});
|
|
||||||
|
|
||||||
// In principle, we only need to do this so long as `impl_source`
|
|
||||||
// contains unbound type parameters. It could be a slight
|
|
||||||
// optimization to stop iterating early.
|
|
||||||
let errors = fulfill_cx.select_all_or_error(&infcx);
|
|
||||||
if !errors.is_empty() {
|
|
||||||
// `rustc_monomorphize::collector` assumes there are no type errors.
|
|
||||||
// Cycle errors are the only post-monomorphization errors possible; emit them now so
|
|
||||||
// `rustc_ty_utils::resolve_associated_item` doesn't return `None` post-monomorphization.
|
|
||||||
for err in errors {
|
|
||||||
if let FulfillmentErrorCode::CodeCycle(cycle) = err.code {
|
|
||||||
infcx.err_ctxt().report_overflow_error_cycle(&cycle);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return Err(CodegenObligationError::FulfillmentError);
|
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
let impl_source = infcx.resolve_vars_if_possible(impl_source);
|
debug!(?selection);
|
||||||
let impl_source = infcx.tcx.erase_regions(impl_source);
|
|
||||||
|
|
||||||
// Opaque types may have gotten their hidden types constrained, but we can ignore them safely
|
// Currently, we use a fulfillment context to completely resolve
|
||||||
// as they will get constrained elsewhere, too.
|
// all nested obligations. This is because they can inform the
|
||||||
// (ouz-a) This is required for `type-alias-impl-trait/assoc-projection-ice.rs` to pass
|
// inference of the impl's type parameters.
|
||||||
let _ = infcx.inner.borrow_mut().opaque_type_storage.take_opaque_types();
|
let mut fulfill_cx = <dyn TraitEngine<'tcx>>::new(tcx);
|
||||||
|
let impl_source = selection.map(|predicate| {
|
||||||
|
fulfill_cx.register_predicate_obligation(&infcx, predicate);
|
||||||
|
});
|
||||||
|
|
||||||
Ok(&*tcx.arena.alloc(impl_source))
|
// In principle, we only need to do this so long as `impl_source`
|
||||||
})
|
// contains unbound type parameters. It could be a slight
|
||||||
|
// optimization to stop iterating early.
|
||||||
|
let errors = fulfill_cx.select_all_or_error(&infcx);
|
||||||
|
if !errors.is_empty() {
|
||||||
|
// `rustc_monomorphize::collector` assumes there are no type errors.
|
||||||
|
// Cycle errors are the only post-monomorphization errors possible; emit them now so
|
||||||
|
// `rustc_ty_utils::resolve_associated_item` doesn't return `None` post-monomorphization.
|
||||||
|
for err in errors {
|
||||||
|
if let FulfillmentErrorCode::CodeCycle(cycle) = err.code {
|
||||||
|
infcx.err_ctxt().report_overflow_error_cycle(&cycle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Err(CodegenObligationError::FulfillmentError);
|
||||||
|
}
|
||||||
|
|
||||||
|
let impl_source = infcx.resolve_vars_if_possible(impl_source);
|
||||||
|
let impl_source = infcx.tcx.erase_regions(impl_source);
|
||||||
|
|
||||||
|
// Opaque types may have gotten their hidden types constrained, but we can ignore them safely
|
||||||
|
// as they will get constrained elsewhere, too.
|
||||||
|
// (ouz-a) This is required for `type-alias-impl-trait/assoc-projection-ice.rs` to pass
|
||||||
|
let _ = infcx.inner.borrow_mut().opaque_type_storage.take_opaque_types();
|
||||||
|
|
||||||
|
Ok(&*tcx.arena.alloc(impl_source))
|
||||||
}
|
}
|
||||||
|
|
|
@ -100,11 +100,10 @@ where
|
||||||
return no_overlap();
|
return no_overlap();
|
||||||
}
|
}
|
||||||
|
|
||||||
let overlaps = tcx.infer_ctxt().enter(|infcx| {
|
let infcx = tcx.infer_ctxt().build();
|
||||||
let selcx = &mut SelectionContext::intercrate(&infcx);
|
let selcx = &mut SelectionContext::intercrate(&infcx);
|
||||||
overlap(selcx, skip_leak_check, impl1_def_id, impl2_def_id, overlap_mode).is_some()
|
let overlaps =
|
||||||
});
|
overlap(selcx, skip_leak_check, impl1_def_id, impl2_def_id, overlap_mode).is_some();
|
||||||
|
|
||||||
if !overlaps {
|
if !overlaps {
|
||||||
return no_overlap();
|
return no_overlap();
|
||||||
}
|
}
|
||||||
|
@ -112,13 +111,10 @@ where
|
||||||
// In the case where we detect an error, run the check again, but
|
// In the case where we detect an error, run the check again, but
|
||||||
// this time tracking intercrate ambiguity causes for better
|
// this time tracking intercrate ambiguity causes for better
|
||||||
// diagnostics. (These take time and can lead to false errors.)
|
// diagnostics. (These take time and can lead to false errors.)
|
||||||
tcx.infer_ctxt().enter(|infcx| {
|
let infcx = tcx.infer_ctxt().build();
|
||||||
let selcx = &mut SelectionContext::intercrate(&infcx);
|
let selcx = &mut SelectionContext::intercrate(&infcx);
|
||||||
selcx.enable_tracking_intercrate_ambiguity_causes();
|
selcx.enable_tracking_intercrate_ambiguity_causes();
|
||||||
on_overlap(
|
on_overlap(overlap(selcx, skip_leak_check, impl1_def_id, impl2_def_id, overlap_mode).unwrap())
|
||||||
overlap(selcx, skip_leak_check, impl1_def_id, impl2_def_id, overlap_mode).unwrap(),
|
|
||||||
)
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn with_fresh_ty_vars<'cx, 'tcx>(
|
fn with_fresh_ty_vars<'cx, 'tcx>(
|
||||||
|
@ -298,33 +294,32 @@ fn negative_impl<'cx, 'tcx>(
|
||||||
let tcx = selcx.infcx().tcx;
|
let tcx = selcx.infcx().tcx;
|
||||||
|
|
||||||
// Create an infcx, taking the predicates of impl1 as assumptions:
|
// Create an infcx, taking the predicates of impl1 as assumptions:
|
||||||
tcx.infer_ctxt().enter(|infcx| {
|
let infcx = tcx.infer_ctxt().build();
|
||||||
// create a parameter environment corresponding to a (placeholder) instantiation of impl1
|
// create a parameter environment corresponding to a (placeholder) instantiation of impl1
|
||||||
let impl_env = tcx.param_env(impl1_def_id);
|
let impl_env = tcx.param_env(impl1_def_id);
|
||||||
let subject1 = match traits::fully_normalize(
|
let subject1 = match traits::fully_normalize(
|
||||||
&infcx,
|
&infcx,
|
||||||
ObligationCause::dummy(),
|
ObligationCause::dummy(),
|
||||||
impl_env,
|
impl_env,
|
||||||
tcx.impl_subject(impl1_def_id),
|
tcx.impl_subject(impl1_def_id),
|
||||||
) {
|
) {
|
||||||
Ok(s) => s,
|
Ok(s) => s,
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
tcx.sess.delay_span_bug(
|
tcx.sess.delay_span_bug(
|
||||||
tcx.def_span(impl1_def_id),
|
tcx.def_span(impl1_def_id),
|
||||||
format!("failed to fully normalize {:?}: {:?}", impl1_def_id, err),
|
format!("failed to fully normalize {:?}: {:?}", impl1_def_id, err),
|
||||||
);
|
);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Attempt to prove that impl2 applies, given all of the above.
|
// Attempt to prove that impl2 applies, given all of the above.
|
||||||
let selcx = &mut SelectionContext::new(&infcx);
|
let selcx = &mut SelectionContext::new(&infcx);
|
||||||
let impl2_substs = infcx.fresh_substs_for_item(DUMMY_SP, impl2_def_id);
|
let impl2_substs = infcx.fresh_substs_for_item(DUMMY_SP, impl2_def_id);
|
||||||
let (subject2, obligations) =
|
let (subject2, obligations) =
|
||||||
impl_subject_and_oblig(selcx, impl_env, impl2_def_id, impl2_substs);
|
impl_subject_and_oblig(selcx, impl_env, impl2_def_id, impl2_substs);
|
||||||
|
|
||||||
!equate(&infcx, impl_env, subject1, subject2, obligations, impl1_def_id)
|
!equate(&infcx, impl_env, subject1, subject2, obligations, impl1_def_id)
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn equate<'tcx>(
|
fn equate<'tcx>(
|
||||||
|
|
|
@ -1930,16 +1930,11 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
let normalize = |candidate| {
|
let normalize = |candidate| {
|
||||||
self.tcx.infer_ctxt().enter(|ref infcx| {
|
let infcx = self.tcx.infer_ctxt().build();
|
||||||
let normalized = infcx
|
infcx
|
||||||
.at(&ObligationCause::dummy(), ty::ParamEnv::empty())
|
.at(&ObligationCause::dummy(), ty::ParamEnv::empty())
|
||||||
.normalize(candidate)
|
.normalize(candidate)
|
||||||
.ok();
|
.map_or(candidate, |normalized| normalized.value)
|
||||||
match normalized {
|
|
||||||
Some(normalized) => normalized.value,
|
|
||||||
None => candidate,
|
|
||||||
}
|
|
||||||
})
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Sort impl candidates so that ordering is consistent for UI tests.
|
// Sort impl candidates so that ordering is consistent for UI tests.
|
||||||
|
|
|
@ -23,65 +23,64 @@ pub fn can_type_implement_copy<'tcx>(
|
||||||
parent_cause: ObligationCause<'tcx>,
|
parent_cause: ObligationCause<'tcx>,
|
||||||
) -> Result<(), CopyImplementationError<'tcx>> {
|
) -> Result<(), CopyImplementationError<'tcx>> {
|
||||||
// FIXME: (@jroesch) float this code up
|
// FIXME: (@jroesch) float this code up
|
||||||
tcx.infer_ctxt().enter(|infcx| {
|
let infcx = tcx.infer_ctxt().build();
|
||||||
let (adt, substs) = match self_type.kind() {
|
let (adt, substs) = match self_type.kind() {
|
||||||
// These types used to have a builtin impl.
|
// These types used to have a builtin impl.
|
||||||
// Now libcore provides that impl.
|
// Now libcore provides that impl.
|
||||||
ty::Uint(_)
|
ty::Uint(_)
|
||||||
| ty::Int(_)
|
| ty::Int(_)
|
||||||
| ty::Bool
|
| ty::Bool
|
||||||
| ty::Float(_)
|
| ty::Float(_)
|
||||||
| ty::Char
|
| ty::Char
|
||||||
| ty::RawPtr(..)
|
| ty::RawPtr(..)
|
||||||
| ty::Never
|
| ty::Never
|
||||||
| ty::Ref(_, _, hir::Mutability::Not)
|
| ty::Ref(_, _, hir::Mutability::Not)
|
||||||
| ty::Array(..) => return Ok(()),
|
| ty::Array(..) => return Ok(()),
|
||||||
|
|
||||||
ty::Adt(adt, substs) => (adt, substs),
|
ty::Adt(adt, substs) => (adt, substs),
|
||||||
|
|
||||||
_ => return Err(CopyImplementationError::NotAnAdt),
|
_ => return Err(CopyImplementationError::NotAnAdt),
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut infringing = Vec::new();
|
let mut infringing = Vec::new();
|
||||||
for variant in adt.variants() {
|
for variant in adt.variants() {
|
||||||
for field in &variant.fields {
|
for field in &variant.fields {
|
||||||
let ty = field.ty(tcx, substs);
|
let ty = field.ty(tcx, substs);
|
||||||
if ty.references_error() {
|
if ty.references_error() {
|
||||||
continue;
|
continue;
|
||||||
}
|
|
||||||
let span = tcx.def_span(field.did);
|
|
||||||
// FIXME(compiler-errors): This gives us better spans for bad
|
|
||||||
// projection types like in issue-50480.
|
|
||||||
// If the ADT has substs, point to the cause we are given.
|
|
||||||
// If it does not, then this field probably doesn't normalize
|
|
||||||
// to begin with, and point to the bad field's span instead.
|
|
||||||
let cause = if field
|
|
||||||
.ty(tcx, traits::InternalSubsts::identity_for_item(tcx, adt.did()))
|
|
||||||
.has_non_region_param()
|
|
||||||
{
|
|
||||||
parent_cause.clone()
|
|
||||||
} else {
|
|
||||||
ObligationCause::dummy_with_span(span)
|
|
||||||
};
|
|
||||||
match traits::fully_normalize(&infcx, cause, param_env, ty) {
|
|
||||||
Ok(ty) => {
|
|
||||||
if !infcx.type_is_copy_modulo_regions(param_env, ty, span) {
|
|
||||||
infringing.push((field, ty));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Err(errors) => {
|
|
||||||
infcx.err_ctxt().report_fulfillment_errors(&errors, None, false);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
let span = tcx.def_span(field.did);
|
||||||
|
// FIXME(compiler-errors): This gives us better spans for bad
|
||||||
|
// projection types like in issue-50480.
|
||||||
|
// If the ADT has substs, point to the cause we are given.
|
||||||
|
// If it does not, then this field probably doesn't normalize
|
||||||
|
// to begin with, and point to the bad field's span instead.
|
||||||
|
let cause = if field
|
||||||
|
.ty(tcx, traits::InternalSubsts::identity_for_item(tcx, adt.did()))
|
||||||
|
.has_non_region_param()
|
||||||
|
{
|
||||||
|
parent_cause.clone()
|
||||||
|
} else {
|
||||||
|
ObligationCause::dummy_with_span(span)
|
||||||
|
};
|
||||||
|
match traits::fully_normalize(&infcx, cause, param_env, ty) {
|
||||||
|
Ok(ty) => {
|
||||||
|
if !infcx.type_is_copy_modulo_regions(param_env, ty, span) {
|
||||||
|
infringing.push((field, ty));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(errors) => {
|
||||||
|
infcx.err_ctxt().report_fulfillment_errors(&errors, None, false);
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
if !infringing.is_empty() {
|
}
|
||||||
return Err(CopyImplementationError::InfrigingFields(infringing));
|
if !infringing.is_empty() {
|
||||||
}
|
return Err(CopyImplementationError::InfrigingFields(infringing));
|
||||||
if adt.has_dtor(tcx) {
|
}
|
||||||
return Err(CopyImplementationError::HasDestructor);
|
if adt.has_dtor(tcx) {
|
||||||
}
|
return Err(CopyImplementationError::HasDestructor);
|
||||||
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -234,54 +234,51 @@ fn do_normalize_predicates<'tcx>(
|
||||||
// by wfcheck anyway, so I'm not sure we have to check
|
// by wfcheck anyway, so I'm not sure we have to check
|
||||||
// them here too, and we will remove this function when
|
// them here too, and we will remove this function when
|
||||||
// we move over to lazy normalization *anyway*.
|
// we move over to lazy normalization *anyway*.
|
||||||
tcx.infer_ctxt().ignoring_regions().enter(|infcx| {
|
let infcx = tcx.infer_ctxt().ignoring_regions().build();
|
||||||
let predicates = match fully_normalize(&infcx, cause, elaborated_env, predicates) {
|
let predicates = match fully_normalize(&infcx, cause, elaborated_env, predicates) {
|
||||||
Ok(predicates) => predicates,
|
Ok(predicates) => predicates,
|
||||||
Err(errors) => {
|
Err(errors) => {
|
||||||
let reported = infcx.err_ctxt().report_fulfillment_errors(&errors, None, false);
|
let reported = infcx.err_ctxt().report_fulfillment_errors(&errors, None, false);
|
||||||
return Err(reported);
|
return Err(reported);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
debug!("do_normalize_predictes: normalized predicates = {:?}", predicates);
|
debug!("do_normalize_predictes: normalized predicates = {:?}", predicates);
|
||||||
|
|
||||||
// We can use the `elaborated_env` here; the region code only
|
// We can use the `elaborated_env` here; the region code only
|
||||||
// cares about declarations like `'a: 'b`.
|
// cares about declarations like `'a: 'b`.
|
||||||
let outlives_env = OutlivesEnvironment::new(elaborated_env);
|
let outlives_env = OutlivesEnvironment::new(elaborated_env);
|
||||||
|
|
||||||
// FIXME: It's very weird that we ignore region obligations but apparently
|
// FIXME: It's very weird that we ignore region obligations but apparently
|
||||||
// still need to use `resolve_regions` as we need the resolved regions in
|
// still need to use `resolve_regions` as we need the resolved regions in
|
||||||
// the normalized predicates.
|
// the normalized predicates.
|
||||||
let errors = infcx.resolve_regions(&outlives_env);
|
let errors = infcx.resolve_regions(&outlives_env);
|
||||||
if !errors.is_empty() {
|
if !errors.is_empty() {
|
||||||
tcx.sess.delay_span_bug(
|
tcx.sess.delay_span_bug(
|
||||||
|
span,
|
||||||
|
format!("failed region resolution while normalizing {elaborated_env:?}: {errors:?}"),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
match infcx.fully_resolve(predicates) {
|
||||||
|
Ok(predicates) => Ok(predicates),
|
||||||
|
Err(fixup_err) => {
|
||||||
|
// If we encounter a fixup error, it means that some type
|
||||||
|
// variable wound up unconstrained. I actually don't know
|
||||||
|
// if this can happen, and I certainly don't expect it to
|
||||||
|
// happen often, but if it did happen it probably
|
||||||
|
// represents a legitimate failure due to some kind of
|
||||||
|
// unconstrained variable.
|
||||||
|
//
|
||||||
|
// @lcnr: Let's still ICE here for now. I want a test case
|
||||||
|
// for that.
|
||||||
|
span_bug!(
|
||||||
span,
|
span,
|
||||||
format!(
|
"inference variables in normalized parameter environment: {}",
|
||||||
"failed region resolution while normalizing {elaborated_env:?}: {errors:?}"
|
fixup_err
|
||||||
),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
match infcx.fully_resolve(predicates) {
|
|
||||||
Ok(predicates) => Ok(predicates),
|
|
||||||
Err(fixup_err) => {
|
|
||||||
// If we encounter a fixup error, it means that some type
|
|
||||||
// variable wound up unconstrained. I actually don't know
|
|
||||||
// if this can happen, and I certainly don't expect it to
|
|
||||||
// happen often, but if it did happen it probably
|
|
||||||
// represents a legitimate failure due to some kind of
|
|
||||||
// unconstrained variable.
|
|
||||||
//
|
|
||||||
// @lcnr: Let's still ICE here for now. I want a test case
|
|
||||||
// for that.
|
|
||||||
span_bug!(
|
|
||||||
span,
|
|
||||||
"inference variables in normalized parameter environment: {}",
|
|
||||||
fixup_err
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: this is gonna need to be removed ...
|
// FIXME: this is gonna need to be removed ...
|
||||||
|
@ -473,21 +470,20 @@ pub fn impossible_predicates<'tcx>(
|
||||||
) -> bool {
|
) -> bool {
|
||||||
debug!("impossible_predicates(predicates={:?})", predicates);
|
debug!("impossible_predicates(predicates={:?})", predicates);
|
||||||
|
|
||||||
let result = tcx.infer_ctxt().enter(|infcx| {
|
let infcx = tcx.infer_ctxt().build();
|
||||||
let param_env = ty::ParamEnv::reveal_all();
|
let param_env = ty::ParamEnv::reveal_all();
|
||||||
let ocx = ObligationCtxt::new(&infcx);
|
let ocx = ObligationCtxt::new(&infcx);
|
||||||
let predicates = ocx.normalize(ObligationCause::dummy(), param_env, predicates);
|
let predicates = ocx.normalize(ObligationCause::dummy(), param_env, predicates);
|
||||||
for predicate in predicates {
|
for predicate in predicates {
|
||||||
let obligation = Obligation::new(ObligationCause::dummy(), param_env, predicate);
|
let obligation = Obligation::new(ObligationCause::dummy(), param_env, predicate);
|
||||||
ocx.register_obligation(obligation);
|
ocx.register_obligation(obligation);
|
||||||
}
|
}
|
||||||
let errors = ocx.select_all_or_error();
|
let errors = ocx.select_all_or_error();
|
||||||
|
|
||||||
// Clean up after ourselves
|
// Clean up after ourselves
|
||||||
let _ = infcx.inner.borrow_mut().opaque_type_storage.take_opaque_types();
|
let _ = infcx.inner.borrow_mut().opaque_type_storage.take_opaque_types();
|
||||||
|
|
||||||
!errors.is_empty()
|
let result = !errors.is_empty();
|
||||||
});
|
|
||||||
debug!("impossible_predicates = {:?}", result);
|
debug!("impossible_predicates = {:?}", result);
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
|
@ -578,18 +574,16 @@ fn is_impossible_method<'tcx>(
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
tcx.infer_ctxt().ignoring_regions().enter(|ref infcx| {
|
let infcx = tcx.infer_ctxt().ignoring_regions().build();
|
||||||
for obligation in predicates_for_trait {
|
for obligation in predicates_for_trait {
|
||||||
// Ignore overflow error, to be conservative.
|
// Ignore overflow error, to be conservative.
|
||||||
if let Ok(result) = infcx.evaluate_obligation(&obligation)
|
if let Ok(result) = infcx.evaluate_obligation(&obligation)
|
||||||
&& !result.may_apply()
|
&& !result.may_apply()
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
false
|
false
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
|
@ -952,10 +946,9 @@ pub fn vtable_trait_upcasting_coercion_new_vptr_slot<'tcx>(
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
let implsrc = tcx.infer_ctxt().enter(|infcx| {
|
let infcx = tcx.infer_ctxt().build();
|
||||||
let mut selcx = SelectionContext::new(&infcx);
|
let mut selcx = SelectionContext::new(&infcx);
|
||||||
selcx.select(&obligation).unwrap()
|
let implsrc = selcx.select(&obligation).unwrap();
|
||||||
});
|
|
||||||
|
|
||||||
let Some(ImplSource::TraitUpcasting(implsrc_traitcasting)) = implsrc else {
|
let Some(ImplSource::TraitUpcasting(implsrc_traitcasting)) = implsrc else {
|
||||||
bug!();
|
bug!();
|
||||||
|
|
|
@ -734,10 +734,9 @@ fn receiver_is_dispatchable<'tcx>(
|
||||||
Obligation::new(ObligationCause::dummy(), param_env, predicate)
|
Obligation::new(ObligationCause::dummy(), param_env, predicate)
|
||||||
};
|
};
|
||||||
|
|
||||||
tcx.infer_ctxt().enter(|ref infcx| {
|
let infcx = tcx.infer_ctxt().build();
|
||||||
// the receiver is dispatchable iff the obligation holds
|
// the receiver is dispatchable iff the obligation holds
|
||||||
infcx.predicate_must_hold_modulo_regions(&obligation)
|
infcx.predicate_must_hold_modulo_regions(&obligation)
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn contains_illegal_self_type_reference<'tcx, T: TypeVisitable<'tcx>>(
|
fn contains_illegal_self_type_reference<'tcx, T: TypeVisitable<'tcx>>(
|
||||||
|
|
|
@ -149,13 +149,9 @@ pub(super) fn specializes(tcx: TyCtxt<'_>, (impl1_def_id, impl2_def_id): (DefId,
|
||||||
let impl1_trait_ref = tcx.impl_trait_ref(impl1_def_id).unwrap();
|
let impl1_trait_ref = tcx.impl_trait_ref(impl1_def_id).unwrap();
|
||||||
|
|
||||||
// Create an infcx, taking the predicates of impl1 as assumptions:
|
// Create an infcx, taking the predicates of impl1 as assumptions:
|
||||||
tcx.infer_ctxt().enter(|infcx| {
|
let infcx = tcx.infer_ctxt().build();
|
||||||
let impl1_trait_ref = match traits::fully_normalize(
|
let impl1_trait_ref =
|
||||||
&infcx,
|
match traits::fully_normalize(&infcx, ObligationCause::dummy(), penv, impl1_trait_ref) {
|
||||||
ObligationCause::dummy(),
|
|
||||||
penv,
|
|
||||||
impl1_trait_ref,
|
|
||||||
) {
|
|
||||||
Ok(impl1_trait_ref) => impl1_trait_ref,
|
Ok(impl1_trait_ref) => impl1_trait_ref,
|
||||||
Err(_errors) => {
|
Err(_errors) => {
|
||||||
tcx.sess.delay_span_bug(
|
tcx.sess.delay_span_bug(
|
||||||
|
@ -166,9 +162,8 @@ pub(super) fn specializes(tcx: TyCtxt<'_>, (impl1_def_id, impl2_def_id): (DefId,
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Attempt to prove that impl2 applies, given all of the above.
|
// Attempt to prove that impl2 applies, given all of the above.
|
||||||
fulfill_implication(&infcx, penv, impl1_trait_ref, impl2_def_id).is_ok()
|
fulfill_implication(&infcx, penv, impl1_trait_ref, impl2_def_id).is_ok()
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Attempt to fulfill all obligations of `target_impl` after unification with
|
/// Attempt to fulfill all obligations of `target_impl` after unification with
|
||||||
|
|
|
@ -265,9 +265,8 @@ impl<'tcx> TypeVisitor<'tcx> for Search<'tcx> {
|
||||||
|
|
||||||
pub fn provide(providers: &mut Providers) {
|
pub fn provide(providers: &mut Providers) {
|
||||||
providers.has_structural_eq_impls = |tcx, ty| {
|
providers.has_structural_eq_impls = |tcx, ty| {
|
||||||
tcx.infer_ctxt().enter(|infcx| {
|
let infcx = tcx.infer_ctxt().build();
|
||||||
let cause = ObligationCause::dummy();
|
let cause = ObligationCause::dummy();
|
||||||
type_marked_structural(&infcx, ty, cause)
|
type_marked_structural(&infcx, ty, cause)
|
||||||
})
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,128 +27,120 @@ fn dropck_outlives<'tcx>(
|
||||||
) -> Result<&'tcx Canonical<'tcx, QueryResponse<'tcx, DropckOutlivesResult<'tcx>>>, NoSolution> {
|
) -> Result<&'tcx Canonical<'tcx, QueryResponse<'tcx, DropckOutlivesResult<'tcx>>>, NoSolution> {
|
||||||
debug!("dropck_outlives(goal={:#?})", canonical_goal);
|
debug!("dropck_outlives(goal={:#?})", canonical_goal);
|
||||||
|
|
||||||
tcx.infer_ctxt().enter_with_canonical(
|
let (ref infcx, goal, canonical_inference_vars) =
|
||||||
DUMMY_SP,
|
tcx.infer_ctxt().build_with_canonical(DUMMY_SP, &canonical_goal);
|
||||||
&canonical_goal,
|
let tcx = infcx.tcx;
|
||||||
|ref infcx, goal, canonical_inference_vars| {
|
let ParamEnvAnd { param_env, value: for_ty } = goal;
|
||||||
let tcx = infcx.tcx;
|
|
||||||
let ParamEnvAnd { param_env, value: for_ty } = goal;
|
|
||||||
|
|
||||||
let mut result = DropckOutlivesResult { kinds: vec![], overflows: vec![] };
|
let mut result = DropckOutlivesResult { kinds: vec![], overflows: vec![] };
|
||||||
|
|
||||||
// A stack of types left to process. Each round, we pop
|
// A stack of types left to process. Each round, we pop
|
||||||
// something from the stack and invoke
|
// something from the stack and invoke
|
||||||
// `dtorck_constraint_for_ty`. This may produce new types that
|
// `dtorck_constraint_for_ty`. This may produce new types that
|
||||||
// have to be pushed on the stack. This continues until we have explored
|
// have to be pushed on the stack. This continues until we have explored
|
||||||
// all the reachable types from the type `for_ty`.
|
// all the reachable types from the type `for_ty`.
|
||||||
//
|
//
|
||||||
// Example: Imagine that we have the following code:
|
// Example: Imagine that we have the following code:
|
||||||
//
|
//
|
||||||
// ```rust
|
// ```rust
|
||||||
// struct A {
|
// struct A {
|
||||||
// value: B,
|
// value: B,
|
||||||
// children: Vec<A>,
|
// children: Vec<A>,
|
||||||
// }
|
// }
|
||||||
//
|
//
|
||||||
// struct B {
|
// struct B {
|
||||||
// value: u32
|
// value: u32
|
||||||
// }
|
// }
|
||||||
//
|
//
|
||||||
// fn f() {
|
// fn f() {
|
||||||
// let a: A = ...;
|
// let a: A = ...;
|
||||||
// ..
|
// ..
|
||||||
// } // here, `a` is dropped
|
// } // here, `a` is dropped
|
||||||
// ```
|
// ```
|
||||||
//
|
//
|
||||||
// at the point where `a` is dropped, we need to figure out
|
// at the point where `a` is dropped, we need to figure out
|
||||||
// which types inside of `a` contain region data that may be
|
// which types inside of `a` contain region data that may be
|
||||||
// accessed by any destructors in `a`. We begin by pushing `A`
|
// accessed by any destructors in `a`. We begin by pushing `A`
|
||||||
// onto the stack, as that is the type of `a`. We will then
|
// onto the stack, as that is the type of `a`. We will then
|
||||||
// invoke `dtorck_constraint_for_ty` which will expand `A`
|
// invoke `dtorck_constraint_for_ty` which will expand `A`
|
||||||
// into the types of its fields `(B, Vec<A>)`. These will get
|
// into the types of its fields `(B, Vec<A>)`. These will get
|
||||||
// pushed onto the stack. Eventually, expanding `Vec<A>` will
|
// pushed onto the stack. Eventually, expanding `Vec<A>` will
|
||||||
// lead to us trying to push `A` a second time -- to prevent
|
// lead to us trying to push `A` a second time -- to prevent
|
||||||
// infinite recursion, we notice that `A` was already pushed
|
// infinite recursion, we notice that `A` was already pushed
|
||||||
// once and stop.
|
// once and stop.
|
||||||
let mut ty_stack = vec![(for_ty, 0)];
|
let mut ty_stack = vec![(for_ty, 0)];
|
||||||
|
|
||||||
// Set used to detect infinite recursion.
|
// Set used to detect infinite recursion.
|
||||||
let mut ty_set = FxHashSet::default();
|
let mut ty_set = FxHashSet::default();
|
||||||
|
|
||||||
let mut fulfill_cx = <dyn TraitEngine<'_>>::new(infcx.tcx);
|
let mut fulfill_cx = <dyn TraitEngine<'_>>::new(infcx.tcx);
|
||||||
|
|
||||||
let cause = ObligationCause::dummy();
|
let cause = ObligationCause::dummy();
|
||||||
let mut constraints = DropckConstraint::empty();
|
let mut constraints = DropckConstraint::empty();
|
||||||
while let Some((ty, depth)) = ty_stack.pop() {
|
while let Some((ty, depth)) = ty_stack.pop() {
|
||||||
debug!(
|
debug!(
|
||||||
"{} kinds, {} overflows, {} ty_stack",
|
"{} kinds, {} overflows, {} ty_stack",
|
||||||
result.kinds.len(),
|
result.kinds.len(),
|
||||||
result.overflows.len(),
|
result.overflows.len(),
|
||||||
ty_stack.len()
|
ty_stack.len()
|
||||||
);
|
);
|
||||||
dtorck_constraint_for_ty(tcx, DUMMY_SP, for_ty, depth, ty, &mut constraints)?;
|
dtorck_constraint_for_ty(tcx, DUMMY_SP, for_ty, depth, ty, &mut constraints)?;
|
||||||
|
|
||||||
// "outlives" represent types/regions that may be touched
|
// "outlives" represent types/regions that may be touched
|
||||||
// by a destructor.
|
// by a destructor.
|
||||||
result.kinds.append(&mut constraints.outlives);
|
result.kinds.append(&mut constraints.outlives);
|
||||||
result.overflows.append(&mut constraints.overflows);
|
result.overflows.append(&mut constraints.overflows);
|
||||||
|
|
||||||
// If we have even one overflow, we should stop trying to evaluate further --
|
// If we have even one overflow, we should stop trying to evaluate further --
|
||||||
// chances are, the subsequent overflows for this evaluation won't provide useful
|
// chances are, the subsequent overflows for this evaluation won't provide useful
|
||||||
// information and will just decrease the speed at which we can emit these errors
|
// information and will just decrease the speed at which we can emit these errors
|
||||||
// (since we'll be printing for just that much longer for the often enormous types
|
// (since we'll be printing for just that much longer for the often enormous types
|
||||||
// that result here).
|
// that result here).
|
||||||
if !result.overflows.is_empty() {
|
if !result.overflows.is_empty() {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// dtorck types are "types that will get dropped but which
|
// dtorck types are "types that will get dropped but which
|
||||||
// do not themselves define a destructor", more or less. We have
|
// do not themselves define a destructor", more or less. We have
|
||||||
// to push them onto the stack to be expanded.
|
// to push them onto the stack to be expanded.
|
||||||
for ty in constraints.dtorck_types.drain(..) {
|
for ty in constraints.dtorck_types.drain(..) {
|
||||||
match infcx.at(&cause, param_env).normalize(ty) {
|
match infcx.at(&cause, param_env).normalize(ty) {
|
||||||
Ok(Normalized { value: ty, obligations }) => {
|
Ok(Normalized { value: ty, obligations }) => {
|
||||||
fulfill_cx.register_predicate_obligations(infcx, obligations);
|
fulfill_cx.register_predicate_obligations(infcx, obligations);
|
||||||
|
|
||||||
debug!("dropck_outlives: ty from dtorck_types = {:?}", ty);
|
debug!("dropck_outlives: ty from dtorck_types = {:?}", ty);
|
||||||
|
|
||||||
match ty.kind() {
|
match ty.kind() {
|
||||||
// All parameters live for the duration of the
|
// All parameters live for the duration of the
|
||||||
// function.
|
// function.
|
||||||
ty::Param(..) => {}
|
ty::Param(..) => {}
|
||||||
|
|
||||||
// A projection that we couldn't resolve - it
|
// A projection that we couldn't resolve - it
|
||||||
// might have a destructor.
|
// might have a destructor.
|
||||||
ty::Projection(..) | ty::Opaque(..) => {
|
ty::Projection(..) | ty::Opaque(..) => {
|
||||||
result.kinds.push(ty.into());
|
result.kinds.push(ty.into());
|
||||||
}
|
|
||||||
|
|
||||||
_ => {
|
|
||||||
if ty_set.insert(ty) {
|
|
||||||
ty_stack.push((ty, depth + 1));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// We don't actually expect to fail to normalize.
|
_ => {
|
||||||
// That implies a WF error somewhere else.
|
if ty_set.insert(ty) {
|
||||||
Err(NoSolution) => {
|
ty_stack.push((ty, depth + 1));
|
||||||
return Err(NoSolution);
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// We don't actually expect to fail to normalize.
|
||||||
|
// That implies a WF error somewhere else.
|
||||||
|
Err(NoSolution) => {
|
||||||
|
return Err(NoSolution);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
debug!("dropck_outlives: result = {:#?}", result);
|
debug!("dropck_outlives: result = {:#?}", result);
|
||||||
|
|
||||||
infcx.make_canonicalized_query_response(
|
infcx.make_canonicalized_query_response(canonical_inference_vars, result, &mut *fulfill_cx)
|
||||||
canonical_inference_vars,
|
|
||||||
result,
|
|
||||||
&mut *fulfill_cx,
|
|
||||||
)
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a set of constraints that needs to be satisfied in
|
/// Returns a set of constraints that needs to be satisfied in
|
||||||
|
|
|
@ -18,17 +18,15 @@ fn evaluate_obligation<'tcx>(
|
||||||
debug!("evaluate_obligation(canonical_goal={:#?})", canonical_goal);
|
debug!("evaluate_obligation(canonical_goal={:#?})", canonical_goal);
|
||||||
// HACK This bubble is required for this tests to pass:
|
// HACK This bubble is required for this tests to pass:
|
||||||
// impl-trait/issue99642.rs
|
// impl-trait/issue99642.rs
|
||||||
tcx.infer_ctxt().with_opaque_type_inference(DefiningAnchor::Bubble).enter_with_canonical(
|
let (ref infcx, goal, _canonical_inference_vars) = tcx
|
||||||
DUMMY_SP,
|
.infer_ctxt()
|
||||||
&canonical_goal,
|
.with_opaque_type_inference(DefiningAnchor::Bubble)
|
||||||
|ref infcx, goal, _canonical_inference_vars| {
|
.build_with_canonical(DUMMY_SP, &canonical_goal);
|
||||||
debug!("evaluate_obligation: goal={:#?}", goal);
|
debug!("evaluate_obligation: goal={:#?}", goal);
|
||||||
let ParamEnvAnd { param_env, value: predicate } = goal;
|
let ParamEnvAnd { param_env, value: predicate } = goal;
|
||||||
|
|
||||||
let mut selcx = SelectionContext::with_query_mode(&infcx, TraitQueryMode::Canonical);
|
let mut selcx = SelectionContext::with_query_mode(&infcx, TraitQueryMode::Canonical);
|
||||||
let obligation = Obligation::new(ObligationCause::dummy(), param_env, predicate);
|
let obligation = Obligation::new(ObligationCause::dummy(), param_env, predicate);
|
||||||
|
|
||||||
selcx.evaluate_root_obligation(&obligation)
|
selcx.evaluate_root_obligation(&obligation)
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,30 +30,29 @@ fn try_normalize_after_erasing_regions<'tcx, T: TypeFoldable<'tcx> + PartialEq +
|
||||||
goal: ParamEnvAnd<'tcx, T>,
|
goal: ParamEnvAnd<'tcx, T>,
|
||||||
) -> Result<T, NoSolution> {
|
) -> Result<T, NoSolution> {
|
||||||
let ParamEnvAnd { param_env, value } = goal;
|
let ParamEnvAnd { param_env, value } = goal;
|
||||||
tcx.infer_ctxt().enter(|infcx| {
|
let infcx = tcx.infer_ctxt().build();
|
||||||
let cause = ObligationCause::dummy();
|
let cause = ObligationCause::dummy();
|
||||||
match infcx.at(&cause, param_env).normalize(value) {
|
match infcx.at(&cause, param_env).normalize(value) {
|
||||||
Ok(Normalized { value: normalized_value, obligations: normalized_obligations }) => {
|
Ok(Normalized { value: normalized_value, obligations: normalized_obligations }) => {
|
||||||
// We don't care about the `obligations`; they are
|
// We don't care about the `obligations`; they are
|
||||||
// always only region relations, and we are about to
|
// always only region relations, and we are about to
|
||||||
// erase those anyway:
|
// erase those anyway:
|
||||||
debug_assert_eq!(
|
debug_assert_eq!(
|
||||||
normalized_obligations.iter().find(|p| not_outlives_predicate(p.predicate)),
|
normalized_obligations.iter().find(|p| not_outlives_predicate(p.predicate)),
|
||||||
None,
|
None,
|
||||||
);
|
);
|
||||||
|
|
||||||
let resolved_value = infcx.resolve_vars_if_possible(normalized_value);
|
let resolved_value = infcx.resolve_vars_if_possible(normalized_value);
|
||||||
// It's unclear when `resolve_vars` would have an effect in a
|
// It's unclear when `resolve_vars` would have an effect in a
|
||||||
// fresh `InferCtxt`. If this assert does trigger, it will give
|
// fresh `InferCtxt`. If this assert does trigger, it will give
|
||||||
// us a test case.
|
// us a test case.
|
||||||
debug_assert_eq!(normalized_value, resolved_value);
|
debug_assert_eq!(normalized_value, resolved_value);
|
||||||
let erased = infcx.tcx.erase_regions(resolved_value);
|
let erased = infcx.tcx.erase_regions(resolved_value);
|
||||||
debug_assert!(!erased.needs_infer(), "{:?}", erased);
|
debug_assert!(!erased.needs_infer(), "{:?}", erased);
|
||||||
Ok(erased)
|
Ok(erased)
|
||||||
}
|
|
||||||
Err(NoSolution) => Err(NoSolution),
|
|
||||||
}
|
}
|
||||||
})
|
Err(NoSolution) => Err(NoSolution),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn not_outlives_predicate<'tcx>(p: ty::Predicate<'tcx>) -> bool {
|
fn not_outlives_predicate<'tcx>(p: ty::Predicate<'tcx>) -> bool {
|
||||||
|
|
|
@ -29,15 +29,8 @@ fn is_item_raw<'tcx>(
|
||||||
) -> bool {
|
) -> bool {
|
||||||
let (param_env, ty) = query.into_parts();
|
let (param_env, ty) = query.into_parts();
|
||||||
let trait_def_id = tcx.require_lang_item(item, None);
|
let trait_def_id = tcx.require_lang_item(item, None);
|
||||||
tcx.infer_ctxt().enter(|infcx| {
|
let infcx = tcx.infer_ctxt().build();
|
||||||
traits::type_known_to_meet_bound_modulo_regions(
|
traits::type_known_to_meet_bound_modulo_regions(&infcx, param_env, ty, trait_def_id, DUMMY_SP)
|
||||||
&infcx,
|
|
||||||
param_env,
|
|
||||||
ty,
|
|
||||||
trait_def_id,
|
|
||||||
DUMMY_SP,
|
|
||||||
)
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn provide(providers: &mut ty::query::Providers) {
|
pub(crate) fn provide(providers: &mut ty::query::Providers) {
|
||||||
|
|
|
@ -134,19 +134,17 @@ fn resolve_associated_item<'tcx>(
|
||||||
.unwrap_or_else(|| {
|
.unwrap_or_else(|| {
|
||||||
bug!("{:?} not found in {:?}", trait_item_id, impl_data.impl_def_id);
|
bug!("{:?} not found in {:?}", trait_item_id, impl_data.impl_def_id);
|
||||||
});
|
});
|
||||||
|
let infcx = tcx.infer_ctxt().build();
|
||||||
let substs = tcx.infer_ctxt().enter(|infcx| {
|
let param_env = param_env.with_reveal_all_normalized(tcx);
|
||||||
let param_env = param_env.with_reveal_all_normalized(tcx);
|
let substs = rcvr_substs.rebase_onto(tcx, trait_def_id, impl_data.substs);
|
||||||
let substs = rcvr_substs.rebase_onto(tcx, trait_def_id, impl_data.substs);
|
let substs = translate_substs(
|
||||||
let substs = translate_substs(
|
&infcx,
|
||||||
&infcx,
|
param_env,
|
||||||
param_env,
|
impl_data.impl_def_id,
|
||||||
impl_data.impl_def_id,
|
substs,
|
||||||
substs,
|
leaf_def.defining_node,
|
||||||
leaf_def.defining_node,
|
);
|
||||||
);
|
let substs = infcx.tcx.erase_regions(substs);
|
||||||
infcx.tcx.erase_regions(substs)
|
|
||||||
});
|
|
||||||
|
|
||||||
// Since this is a trait item, we need to see if the item is either a trait default item
|
// Since this is a trait item, we need to see if the item is either a trait default item
|
||||||
// or a specialization because we can't resolve those unless we can `Reveal::All`.
|
// or a specialization because we can't resolve those unless we can `Reveal::All`.
|
||||||
|
|
|
@ -27,76 +27,70 @@ impl<'a, 'tcx> BlanketImplFinder<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
// NOTE: doesn't use `for_each_relevant_impl` to avoid looking at anything besides blanket impls
|
// NOTE: doesn't use `for_each_relevant_impl` to avoid looking at anything besides blanket impls
|
||||||
let trait_impls = cx.tcx.trait_impls_of(trait_def_id);
|
let trait_impls = cx.tcx.trait_impls_of(trait_def_id);
|
||||||
for &impl_def_id in trait_impls.blanket_impls() {
|
'blanket_impls: for &impl_def_id in trait_impls.blanket_impls() {
|
||||||
trace!(
|
trace!(
|
||||||
"get_blanket_impls: Considering impl for trait '{:?}' {:?}",
|
"get_blanket_impls: Considering impl for trait '{:?}' {:?}",
|
||||||
trait_def_id,
|
trait_def_id,
|
||||||
impl_def_id
|
impl_def_id
|
||||||
);
|
);
|
||||||
let trait_ref = cx.tcx.bound_impl_trait_ref(impl_def_id).unwrap();
|
let trait_ref = cx.tcx.bound_impl_trait_ref(impl_def_id).unwrap();
|
||||||
let is_param = matches!(trait_ref.0.self_ty().kind(), ty::Param(_));
|
if !matches!(trait_ref.0.self_ty().kind(), ty::Param(_)) {
|
||||||
let may_apply = is_param && cx.tcx.infer_ctxt().enter(|infcx| {
|
|
||||||
let substs = infcx.fresh_substs_for_item(DUMMY_SP, item_def_id);
|
|
||||||
let ty = ty.subst(infcx.tcx, substs);
|
|
||||||
let param_env = EarlyBinder(param_env).subst(infcx.tcx, substs);
|
|
||||||
|
|
||||||
let impl_substs = infcx.fresh_substs_for_item(DUMMY_SP, impl_def_id);
|
|
||||||
let trait_ref = trait_ref.subst(infcx.tcx, impl_substs);
|
|
||||||
|
|
||||||
// Require the type the impl is implemented on to match
|
|
||||||
// our type, and ignore the impl if there was a mismatch.
|
|
||||||
let cause = traits::ObligationCause::dummy();
|
|
||||||
let eq_result = infcx.at(&cause, param_env).eq(trait_ref.self_ty(), ty);
|
|
||||||
if let Ok(InferOk { value: (), obligations }) = eq_result {
|
|
||||||
// FIXME(eddyb) ignoring `obligations` might cause false positives.
|
|
||||||
drop(obligations);
|
|
||||||
|
|
||||||
trace!(
|
|
||||||
"invoking predicate_may_hold: param_env={:?}, trait_ref={:?}, ty={:?}",
|
|
||||||
param_env,
|
|
||||||
trait_ref,
|
|
||||||
ty
|
|
||||||
);
|
|
||||||
let predicates = cx
|
|
||||||
.tcx
|
|
||||||
.predicates_of(impl_def_id)
|
|
||||||
.instantiate(cx.tcx, impl_substs)
|
|
||||||
.predicates
|
|
||||||
.into_iter()
|
|
||||||
.chain(Some(
|
|
||||||
ty::Binder::dummy(trait_ref)
|
|
||||||
.to_poly_trait_predicate()
|
|
||||||
.map_bound(ty::PredicateKind::Trait)
|
|
||||||
.to_predicate(infcx.tcx),
|
|
||||||
));
|
|
||||||
for predicate in predicates {
|
|
||||||
debug!("testing predicate {:?}", predicate);
|
|
||||||
let obligation = traits::Obligation::new(
|
|
||||||
traits::ObligationCause::dummy(),
|
|
||||||
param_env,
|
|
||||||
predicate,
|
|
||||||
);
|
|
||||||
match infcx.evaluate_obligation(&obligation) {
|
|
||||||
Ok(eval_result) if eval_result.may_apply() => {}
|
|
||||||
Err(traits::OverflowError::Canonical) => {}
|
|
||||||
Err(traits::OverflowError::ErrorReporting) => {}
|
|
||||||
_ => {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
true
|
|
||||||
} else {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
});
|
|
||||||
debug!(
|
|
||||||
"get_blanket_impls: found applicable impl: {} for trait_ref={:?}, ty={:?}",
|
|
||||||
may_apply, trait_ref, ty
|
|
||||||
);
|
|
||||||
if !may_apply {
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
let infcx = cx.tcx.infer_ctxt().build();
|
||||||
|
let substs = infcx.fresh_substs_for_item(DUMMY_SP, item_def_id);
|
||||||
|
let impl_ty = ty.subst(infcx.tcx, substs);
|
||||||
|
let param_env = EarlyBinder(param_env).subst(infcx.tcx, substs);
|
||||||
|
|
||||||
|
let impl_substs = infcx.fresh_substs_for_item(DUMMY_SP, impl_def_id);
|
||||||
|
let impl_trait_ref = trait_ref.subst(infcx.tcx, impl_substs);
|
||||||
|
|
||||||
|
// Require the type the impl is implemented on to match
|
||||||
|
// our type, and ignore the impl if there was a mismatch.
|
||||||
|
let cause = traits::ObligationCause::dummy();
|
||||||
|
let Ok(eq_result) = infcx.at(&cause, param_env).eq(impl_trait_ref.self_ty(), impl_ty) else {
|
||||||
|
continue
|
||||||
|
};
|
||||||
|
let InferOk { value: (), obligations } = eq_result;
|
||||||
|
// FIXME(eddyb) ignoring `obligations` might cause false positives.
|
||||||
|
drop(obligations);
|
||||||
|
|
||||||
|
trace!(
|
||||||
|
"invoking predicate_may_hold: param_env={:?}, impl_trait_ref={:?}, impl_ty={:?}",
|
||||||
|
param_env,
|
||||||
|
impl_trait_ref,
|
||||||
|
impl_ty
|
||||||
|
);
|
||||||
|
let predicates = cx
|
||||||
|
.tcx
|
||||||
|
.predicates_of(impl_def_id)
|
||||||
|
.instantiate(cx.tcx, impl_substs)
|
||||||
|
.predicates
|
||||||
|
.into_iter()
|
||||||
|
.chain(Some(
|
||||||
|
ty::Binder::dummy(impl_trait_ref)
|
||||||
|
.to_poly_trait_predicate()
|
||||||
|
.map_bound(ty::PredicateKind::Trait)
|
||||||
|
.to_predicate(infcx.tcx),
|
||||||
|
));
|
||||||
|
for predicate in predicates {
|
||||||
|
debug!("testing predicate {:?}", predicate);
|
||||||
|
let obligation = traits::Obligation::new(
|
||||||
|
traits::ObligationCause::dummy(),
|
||||||
|
param_env,
|
||||||
|
predicate,
|
||||||
|
);
|
||||||
|
match infcx.evaluate_obligation(&obligation) {
|
||||||
|
Ok(eval_result) if eval_result.may_apply() => {}
|
||||||
|
Err(traits::OverflowError::Canonical) => {}
|
||||||
|
Err(traits::OverflowError::ErrorReporting) => {}
|
||||||
|
_ => continue 'blanket_impls,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
debug!(
|
||||||
|
"get_blanket_impls: found applicable impl for trait_ref={:?}, ty={:?}",
|
||||||
|
trait_ref, ty
|
||||||
|
);
|
||||||
|
|
||||||
cx.generated_synthetics.insert((ty.0, trait_def_id));
|
cx.generated_synthetics.insert((ty.0, trait_def_id));
|
||||||
|
|
||||||
|
|
|
@ -1564,12 +1564,11 @@ fn normalize<'tcx>(cx: &mut DocContext<'tcx>, ty: Ty<'_>) -> Option<Ty<'tcx>> {
|
||||||
|
|
||||||
// Try to normalize `<X as Y>::T` to a type
|
// Try to normalize `<X as Y>::T` to a type
|
||||||
let lifted = ty.lift_to_tcx(cx.tcx).unwrap();
|
let lifted = ty.lift_to_tcx(cx.tcx).unwrap();
|
||||||
let normalized = cx.tcx.infer_ctxt().enter(|infcx| {
|
let infcx = cx.tcx.infer_ctxt().build();
|
||||||
infcx
|
let normalized = infcx
|
||||||
.at(&ObligationCause::dummy(), cx.param_env)
|
.at(&ObligationCause::dummy(), cx.param_env)
|
||||||
.normalize(lifted)
|
.normalize(lifted)
|
||||||
.map(|resolved| infcx.resolve_vars_if_possible(resolved.value))
|
.map(|resolved| infcx.resolve_vars_if_possible(resolved.value));
|
||||||
});
|
|
||||||
match normalized {
|
match normalized {
|
||||||
Ok(normalized_value) => {
|
Ok(normalized_value) => {
|
||||||
debug!("normalized {:?} to {:?}", ty, normalized_value);
|
debug!("normalized {:?} to {:?}", ty, normalized_value);
|
||||||
|
|
|
@ -831,11 +831,10 @@ fn walk_parents<'tcx>(
|
||||||
// Trait methods taking `self`
|
// Trait methods taking `self`
|
||||||
arg_ty
|
arg_ty
|
||||||
} && impl_ty.is_ref()
|
} && impl_ty.is_ref()
|
||||||
&& cx.tcx.infer_ctxt().enter(|infcx|
|
&& let infcx = cx.tcx.infer_ctxt().build()
|
||||||
infcx
|
&& infcx
|
||||||
.type_implements_trait(trait_id, impl_ty, subs, cx.param_env)
|
.type_implements_trait(trait_id, impl_ty, subs, cx.param_env)
|
||||||
.must_apply_modulo_regions()
|
.must_apply_modulo_regions()
|
||||||
)
|
|
||||||
{
|
{
|
||||||
return Some(Position::MethodReceiverRefImpl)
|
return Some(Position::MethodReceiverRefImpl)
|
||||||
}
|
}
|
||||||
|
@ -1119,9 +1118,8 @@ fn needless_borrow_impl_arg_position<'tcx>(
|
||||||
|
|
||||||
let predicate = EarlyBinder(predicate).subst(cx.tcx, &substs_with_referent_ty);
|
let predicate = EarlyBinder(predicate).subst(cx.tcx, &substs_with_referent_ty);
|
||||||
let obligation = Obligation::new(ObligationCause::dummy(), cx.param_env, predicate);
|
let obligation = Obligation::new(ObligationCause::dummy(), cx.param_env, predicate);
|
||||||
cx.tcx
|
let infcx = cx.tcx.infer_ctxt().build();
|
||||||
.infer_ctxt()
|
infcx.predicate_must_hold_modulo_regions(&obligation)
|
||||||
.enter(|infcx| infcx.predicate_must_hold_modulo_regions(&obligation))
|
|
||||||
})
|
})
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -106,9 +106,8 @@ impl<'tcx> LateLintPass<'tcx> for BoxedLocal {
|
||||||
};
|
};
|
||||||
|
|
||||||
let fn_def_id = cx.tcx.hir().local_def_id(hir_id);
|
let fn_def_id = cx.tcx.hir().local_def_id(hir_id);
|
||||||
cx.tcx.infer_ctxt().enter(|infcx| {
|
let infcx = cx.tcx.infer_ctxt().build();
|
||||||
ExprUseVisitor::new(&mut v, &infcx, fn_def_id, cx.param_env, cx.typeck_results()).consume_body(body);
|
ExprUseVisitor::new(&mut v, &infcx, fn_def_id, cx.param_env, cx.typeck_results()).consume_body(body);
|
||||||
});
|
|
||||||
|
|
||||||
for node in v.set {
|
for node in v.set {
|
||||||
span_lint_hir(
|
span_lint_hir(
|
||||||
|
|
|
@ -77,10 +77,9 @@ impl<'tcx> LateLintPass<'tcx> for FutureNotSend {
|
||||||
if is_future {
|
if is_future {
|
||||||
let send_trait = cx.tcx.get_diagnostic_item(sym::Send).unwrap();
|
let send_trait = cx.tcx.get_diagnostic_item(sym::Send).unwrap();
|
||||||
let span = decl.output.span();
|
let span = decl.output.span();
|
||||||
let send_errors = cx.tcx.infer_ctxt().enter(|infcx| {
|
let infcx = cx.tcx.infer_ctxt().build();
|
||||||
let cause = traits::ObligationCause::misc(span, hir_id);
|
let cause = traits::ObligationCause::misc(span, hir_id);
|
||||||
traits::fully_solve_bound(&infcx, cause, cx.param_env, ret_ty, send_trait)
|
let send_errors = traits::fully_solve_bound(&infcx, cause, cx.param_env, ret_ty, send_trait);
|
||||||
});
|
|
||||||
if !send_errors.is_empty() {
|
if !send_errors.is_empty() {
|
||||||
span_lint_and_then(
|
span_lint_and_then(
|
||||||
cx,
|
cx,
|
||||||
|
@ -88,18 +87,18 @@ impl<'tcx> LateLintPass<'tcx> for FutureNotSend {
|
||||||
span,
|
span,
|
||||||
"future cannot be sent between threads safely",
|
"future cannot be sent between threads safely",
|
||||||
|db| {
|
|db| {
|
||||||
cx.tcx.infer_ctxt().enter(|infcx| {
|
for FulfillmentError { obligation, .. } in send_errors {
|
||||||
for FulfillmentError { obligation, .. } in send_errors {
|
infcx
|
||||||
infcx.err_ctxt().maybe_note_obligation_cause_for_async_await(db, &obligation);
|
.err_ctxt()
|
||||||
if let Trait(trait_pred) = obligation.predicate.kind().skip_binder() {
|
.maybe_note_obligation_cause_for_async_await(db, &obligation);
|
||||||
db.note(&format!(
|
if let Trait(trait_pred) = obligation.predicate.kind().skip_binder() {
|
||||||
"`{}` doesn't implement `{}`",
|
db.note(&format!(
|
||||||
trait_pred.self_ty(),
|
"`{}` doesn't implement `{}`",
|
||||||
trait_pred.trait_ref.print_only_trait_path(),
|
trait_pred.self_ty(),
|
||||||
));
|
trait_pred.trait_ref.print_only_trait_path(),
|
||||||
}
|
));
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -65,16 +65,15 @@ fn check_for_mutation<'tcx>(
|
||||||
span_low: None,
|
span_low: None,
|
||||||
span_high: None,
|
span_high: None,
|
||||||
};
|
};
|
||||||
cx.tcx.infer_ctxt().enter(|infcx| {
|
let infcx = cx.tcx.infer_ctxt().build();
|
||||||
ExprUseVisitor::new(
|
ExprUseVisitor::new(
|
||||||
&mut delegate,
|
&mut delegate,
|
||||||
&infcx,
|
&infcx,
|
||||||
body.hir_id.owner.def_id,
|
body.hir_id.owner.def_id,
|
||||||
cx.param_env,
|
cx.param_env,
|
||||||
cx.typeck_results(),
|
cx.typeck_results(),
|
||||||
)
|
)
|
||||||
.walk_expr(body);
|
.walk_expr(body);
|
||||||
});
|
|
||||||
|
|
||||||
delegate.mutation_span()
|
delegate.mutation_span()
|
||||||
}
|
}
|
||||||
|
|
|
@ -420,9 +420,7 @@ fn can_change_type<'a>(cx: &LateContext<'a>, mut expr: &'a Expr<'a>, mut ty: Ty<
|
||||||
if trait_predicates.any(|predicate| {
|
if trait_predicates.any(|predicate| {
|
||||||
let predicate = EarlyBinder(predicate).subst(cx.tcx, new_subst);
|
let predicate = EarlyBinder(predicate).subst(cx.tcx, new_subst);
|
||||||
let obligation = Obligation::new(ObligationCause::dummy(), cx.param_env, predicate);
|
let obligation = Obligation::new(ObligationCause::dummy(), cx.param_env, predicate);
|
||||||
!cx.tcx
|
!cx.tcx.infer_ctxt().build().predicate_must_hold_modulo_regions(&obligation)
|
||||||
.infer_ctxt()
|
|
||||||
.enter(|infcx| infcx.predicate_must_hold_modulo_regions(&obligation))
|
|
||||||
}) {
|
}) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -138,10 +138,8 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByValue {
|
||||||
..
|
..
|
||||||
} = {
|
} = {
|
||||||
let mut ctx = MovedVariablesCtxt::default();
|
let mut ctx = MovedVariablesCtxt::default();
|
||||||
cx.tcx.infer_ctxt().enter(|infcx| {
|
let infcx = cx.tcx.infer_ctxt().build();
|
||||||
euv::ExprUseVisitor::new(&mut ctx, &infcx, fn_def_id, cx.param_env, cx.typeck_results())
|
euv::ExprUseVisitor::new(&mut ctx, &infcx, fn_def_id, cx.param_env, cx.typeck_results()).consume_body(body);
|
||||||
.consume_body(body);
|
|
||||||
});
|
|
||||||
ctx
|
ctx
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -123,16 +123,15 @@ fn imm_borrows_in_expr(cx: &LateContext<'_>, e: &hir::Expr<'_>) -> hir::HirIdSet
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut s = S(hir::HirIdSet::default());
|
let mut s = S(hir::HirIdSet::default());
|
||||||
cx.tcx.infer_ctxt().enter(|infcx| {
|
let infcx = cx.tcx.infer_ctxt().build();
|
||||||
let mut v = ExprUseVisitor::new(
|
let mut v = ExprUseVisitor::new(
|
||||||
&mut s,
|
&mut s,
|
||||||
&infcx,
|
&infcx,
|
||||||
cx.tcx.hir().body_owner_def_id(cx.enclosing_body.unwrap()),
|
cx.tcx.hir().body_owner_def_id(cx.enclosing_body.unwrap()),
|
||||||
cx.param_env,
|
cx.param_env,
|
||||||
cx.typeck_results(),
|
cx.typeck_results(),
|
||||||
);
|
);
|
||||||
v.consume_expr(e);
|
v.consume_expr(e);
|
||||||
});
|
|
||||||
s.0
|
s.0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -156,15 +155,14 @@ fn mut_borrows_in_expr(cx: &LateContext<'_>, e: &hir::Expr<'_>) -> hir::HirIdSet
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut s = S(hir::HirIdSet::default());
|
let mut s = S(hir::HirIdSet::default());
|
||||||
cx.tcx.infer_ctxt().enter(|infcx| {
|
let infcx = cx.tcx.infer_ctxt().build();
|
||||||
let mut v = ExprUseVisitor::new(
|
let mut v = ExprUseVisitor::new(
|
||||||
&mut s,
|
&mut s,
|
||||||
&infcx,
|
&infcx,
|
||||||
cx.tcx.hir().body_owner_def_id(cx.enclosing_body.unwrap()),
|
cx.tcx.hir().body_owner_def_id(cx.enclosing_body.unwrap()),
|
||||||
cx.param_env,
|
cx.param_env,
|
||||||
cx.typeck_results(),
|
cx.typeck_results(),
|
||||||
);
|
);
|
||||||
v.consume_expr(e);
|
v.consume_expr(e);
|
||||||
});
|
|
||||||
s.0
|
s.0
|
||||||
}
|
}
|
||||||
|
|
|
@ -821,10 +821,9 @@ pub fn deref_closure_args<'tcx>(cx: &LateContext<'_>, closure: &'tcx hir::Expr<'
|
||||||
};
|
};
|
||||||
|
|
||||||
let fn_def_id = cx.tcx.hir().local_def_id(closure.hir_id);
|
let fn_def_id = cx.tcx.hir().local_def_id(closure.hir_id);
|
||||||
cx.tcx.infer_ctxt().enter(|infcx| {
|
let infcx = cx.tcx.infer_ctxt().build();
|
||||||
ExprUseVisitor::new(&mut visitor, &infcx, fn_def_id, cx.param_env, cx.typeck_results())
|
ExprUseVisitor::new(&mut visitor, &infcx, fn_def_id, cx.param_env, cx.typeck_results())
|
||||||
.consume_body(closure_body);
|
.consume_body(closure_body);
|
||||||
});
|
|
||||||
|
|
||||||
if !visitor.suggestion_start.is_empty() {
|
if !visitor.suggestion_start.is_empty() {
|
||||||
return Some(DerefClosure {
|
return Some(DerefClosure {
|
||||||
|
|
|
@ -172,11 +172,10 @@ pub fn implements_trait_with_env<'tcx>(
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
let ty_params = tcx.mk_substs(ty_params.iter());
|
let ty_params = tcx.mk_substs(ty_params.iter());
|
||||||
tcx.infer_ctxt().enter(|infcx| {
|
let infcx = tcx.infer_ctxt().build();
|
||||||
infcx
|
infcx
|
||||||
.type_implements_trait(trait_id, ty, ty_params, param_env)
|
.type_implements_trait(trait_id, ty, ty_params, param_env)
|
||||||
.must_apply_modulo_regions()
|
.must_apply_modulo_regions()
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Checks whether this type implements `Drop`.
|
/// Checks whether this type implements `Drop`.
|
||||||
|
@ -242,27 +241,26 @@ fn is_normalizable_helper<'tcx>(
|
||||||
}
|
}
|
||||||
// prevent recursive loops, false-negative is better than endless loop leading to stack overflow
|
// prevent recursive loops, false-negative is better than endless loop leading to stack overflow
|
||||||
cache.insert(ty, false);
|
cache.insert(ty, false);
|
||||||
let result = cx.tcx.infer_ctxt().enter(|infcx| {
|
let infcx = cx.tcx.infer_ctxt().build();
|
||||||
let cause = rustc_middle::traits::ObligationCause::dummy();
|
let cause = rustc_middle::traits::ObligationCause::dummy();
|
||||||
if infcx.at(&cause, param_env).normalize(ty).is_ok() {
|
let result = if infcx.at(&cause, param_env).normalize(ty).is_ok() {
|
||||||
match ty.kind() {
|
match ty.kind() {
|
||||||
ty::Adt(def, substs) => def.variants().iter().all(|variant| {
|
ty::Adt(def, substs) => def.variants().iter().all(|variant| {
|
||||||
variant
|
variant
|
||||||
.fields
|
.fields
|
||||||
.iter()
|
.iter()
|
||||||
.all(|field| is_normalizable_helper(cx, param_env, field.ty(cx.tcx, substs), cache))
|
.all(|field| is_normalizable_helper(cx, param_env, field.ty(cx.tcx, substs), cache))
|
||||||
}),
|
}),
|
||||||
_ => ty.walk().all(|generic_arg| match generic_arg.unpack() {
|
_ => ty.walk().all(|generic_arg| match generic_arg.unpack() {
|
||||||
GenericArgKind::Type(inner_ty) if inner_ty != ty => {
|
GenericArgKind::Type(inner_ty) if inner_ty != ty => {
|
||||||
is_normalizable_helper(cx, param_env, inner_ty, cache)
|
is_normalizable_helper(cx, param_env, inner_ty, cache)
|
||||||
},
|
},
|
||||||
_ => true, // if inner_ty == ty, we've already checked it
|
_ => true, // if inner_ty == ty, we've already checked it
|
||||||
}),
|
}),
|
||||||
}
|
|
||||||
} else {
|
|
||||||
false
|
|
||||||
}
|
}
|
||||||
});
|
} else {
|
||||||
|
false
|
||||||
|
};
|
||||||
cache.insert(ty, result);
|
cache.insert(ty, result);
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,16 +18,15 @@ pub fn mutated_variables<'tcx>(expr: &'tcx Expr<'_>, cx: &LateContext<'tcx>) ->
|
||||||
used_mutably: HirIdSet::default(),
|
used_mutably: HirIdSet::default(),
|
||||||
skip: false,
|
skip: false,
|
||||||
};
|
};
|
||||||
cx.tcx.infer_ctxt().enter(|infcx| {
|
let infcx = cx.tcx.infer_ctxt().build();
|
||||||
ExprUseVisitor::new(
|
ExprUseVisitor::new(
|
||||||
&mut delegate,
|
&mut delegate,
|
||||||
&infcx,
|
&infcx,
|
||||||
expr.hir_id.owner.def_id,
|
expr.hir_id.owner.def_id,
|
||||||
cx.param_env,
|
cx.param_env,
|
||||||
cx.typeck_results(),
|
cx.typeck_results(),
|
||||||
)
|
)
|
||||||
.walk_expr(expr);
|
.walk_expr(expr);
|
||||||
});
|
|
||||||
|
|
||||||
if delegate.skip {
|
if delegate.skip {
|
||||||
return None;
|
return None;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue