Skip to content

Commit

Permalink
Auto merge of #109119 - lcnr:trait-system-cleanup, r=compiler-errors
Browse files Browse the repository at this point in the history
a general type system cleanup

removes the helper functions `traits::fully_solve_X` as they add more complexity then they are worth. It's confusing which of these helpers should be used in which context.

changes the way we deal with overflow to always add depth in `evaluate_predicates_recursively`. It may make sense to actually fully transition to not have `recursion_depth` on obligations but that's probably a bit too much for this PR.

also removes some other small - and imo unnecessary - helpers.

r? types
  • Loading branch information
bors committed Mar 22, 2023
2 parents 5fa73a7 + b8541eb commit 9bdb488
Show file tree
Hide file tree
Showing 39 changed files with 258 additions and 384 deletions.
21 changes: 7 additions & 14 deletions compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ use rustc_span::hygiene::DesugaringKind;
use rustc_span::symbol::{kw, sym};
use rustc_span::{BytePos, Span, Symbol};
use rustc_trait_selection::infer::InferCtxtExt;
use rustc_trait_selection::traits::ObligationCtxt;

use crate::borrow_set::TwoPhaseActivation;
use crate::borrowck_errors;
Expand Down Expand Up @@ -760,20 +761,12 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
else { return; };
// Try to find predicates on *generic params* that would allow copying `ty`
let infcx = tcx.infer_ctxt().build();
let copy_did = infcx.tcx.require_lang_item(LangItem::Copy, Some(span));
let cause = ObligationCause::new(
span,
self.mir_def_id(),
rustc_infer::traits::ObligationCauseCode::MiscObligation,
);
let errors = rustc_trait_selection::traits::fully_solve_bound(
&infcx,
cause,
self.param_env,
// Erase any region vids from the type, which may not be resolved
infcx.tcx.erase_regions(ty),
copy_did,
);
let ocx = ObligationCtxt::new(&infcx);
let copy_did = tcx.require_lang_item(LangItem::Copy, Some(span));
let cause = ObligationCause::misc(span, self.mir_def_id());

ocx.register_bound(cause, self.param_env, infcx.tcx.erase_regions(ty), copy_did);
let errors = ocx.select_all_or_error();

// Only emit suggestion if all required predicates are on generic
let predicates: Result<Vec<_>, _> = errors
Expand Down
1 change: 0 additions & 1 deletion compiler/rustc_borrowck/src/diagnostics/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1078,7 +1078,6 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
self.param_env,
tcx.mk_imm_ref(tcx.lifetimes.re_erased, tcx.erase_regions(ty)),
def_id,
DUMMY_SP,
)
}
_ => false,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use rustc_middle::mir;
use rustc_middle::mir::*;
use rustc_middle::ty::{self, subst::SubstsRef, AdtDef, Ty};
use rustc_trait_selection::traits::{
self, ImplSource, Obligation, ObligationCause, SelectionContext,
self, ImplSource, Obligation, ObligationCause, ObligationCtxt, SelectionContext,
};

use super::ConstCx;
Expand Down Expand Up @@ -184,7 +184,10 @@ impl Qualif for NeedsNonConstDrop {
}

// If we had any errors, then it's bad
!traits::fully_solve_obligations(&infcx, impl_src.nested_obligations()).is_empty()
let ocx = ObligationCtxt::new(&infcx);
ocx.register_obligations(impl_src.nested_obligations());
let errors = ocx.select_all_or_error();
!errors.is_empty()
}

fn in_adt_inherently<'tcx>(
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_hir_analysis/src/check/intrinsic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ fn equate_intrinsic_type<'tcx>(
require_same_types(
tcx,
&cause,
ty::ParamEnv::empty(), // FIXME: do all intrinsics have an empty param env?
tcx.mk_fn_ptr(tcx.fn_sig(it.owner_id).subst_identity()),
fty,
);
Expand Down
33 changes: 18 additions & 15 deletions compiler/rustc_hir_analysis/src/coherence/builtin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,14 @@ use rustc_hir::ItemKind;
use rustc_infer::infer::outlives::env::OutlivesEnvironment;
use rustc_infer::infer::{self, RegionResolutionError};
use rustc_infer::infer::{DefineOpaqueTypes, TyCtxtInferExt};
use rustc_infer::traits::Obligation;
use rustc_middle::ty::adjustment::CoerceUnsizedInfo;
use rustc_middle::ty::{self, suggest_constraining_type_params, Ty, TyCtxt, TypeVisitableExt};
use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt;
use rustc_trait_selection::traits::misc::{
type_allowed_to_implement_copy, CopyImplementationError, InfringingFieldsReason,
};
use rustc_trait_selection::traits::predicate_for_trait_def;
use rustc_trait_selection::traits::ObligationCtxt;
use rustc_trait_selection::traits::{self, ObligationCause};
use std::collections::BTreeMap;

Expand Down Expand Up @@ -334,19 +335,19 @@ fn visit_implementation_of_dispatch_from_dyn(tcx: TyCtxt<'_>, impl_did: LocalDef
))
.emit();
} else {
let errors = traits::fully_solve_obligations(
&infcx,
coerced_fields.into_iter().map(|field| {
predicate_for_trait_def(
tcx,
param_env,
cause.clone(),
let ocx = ObligationCtxt::new(&infcx);
for field in coerced_fields {
ocx.register_obligation(Obligation::new(
tcx,
cause.clone(),
param_env,
ty::Binder::dummy(tcx.mk_trait_ref(
dispatch_from_dyn_trait,
0,
[field.ty(tcx, substs_a), field.ty(tcx, substs_b)],
)
}),
);
)),
));
}
let errors = ocx.select_all_or_error();
if !errors.is_empty() {
infcx.err_ctxt().report_fulfillment_errors(&errors);
}
Expand Down Expand Up @@ -580,10 +581,12 @@ pub fn coerce_unsized_info<'tcx>(tcx: TyCtxt<'tcx>, impl_did: LocalDefId) -> Coe
};

// Register an obligation for `A: Trait<B>`.
let ocx = ObligationCtxt::new(&infcx);
let cause = traits::ObligationCause::misc(span, impl_did);
let predicate =
predicate_for_trait_def(tcx, param_env, cause, trait_def_id, 0, [source, target]);
let errors = traits::fully_solve_obligation(&infcx, predicate);
let obligation =
Obligation::new(tcx, cause, param_env, tcx.mk_trait_ref(trait_def_id, [source, target]));
ocx.register_obligation(obligation);
let errors = ocx.select_all_or_error();
if !errors.is_empty() {
infcx.err_ctxt().report_fulfillment_errors(&errors);
}
Expand Down
42 changes: 21 additions & 21 deletions compiler/rustc_hir_analysis/src/hir_wf_check.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use rustc_infer::traits::{ObligationCause, WellFormedLoc};
use rustc_middle::ty::query::Providers;
use rustc_middle::ty::{self, Region, TyCtxt, TypeFoldable, TypeFolder};
use rustc_span::def_id::LocalDefId;
use rustc_trait_selection::traits;
use rustc_trait_selection::traits::{self, ObligationCtxt};

pub fn provide(providers: &mut Providers) {
*providers = Providers { diagnostic_hir_wf_check, ..*providers };
Expand Down Expand Up @@ -66,35 +66,35 @@ fn diagnostic_hir_wf_check<'tcx>(
impl<'tcx> Visitor<'tcx> for HirWfCheck<'tcx> {
fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx>) {
let infcx = self.tcx.infer_ctxt().build();
let ocx = ObligationCtxt::new(&infcx);

let tcx_ty = self.icx.to_ty(ty).fold_with(&mut EraseAllBoundRegions { tcx: self.tcx });
let cause = traits::ObligationCause::new(
ty.span,
self.def_id,
traits::ObligationCauseCode::WellFormed(None),
);
let errors = traits::fully_solve_obligation(
&infcx,
traits::Obligation::new(
self.tcx,
cause,
self.param_env,
ty::Binder::dummy(ty::PredicateKind::WellFormed(tcx_ty.into())),
),
);
if !errors.is_empty() {
debug!("Wf-check got errors for {:?}: {:?}", ty, errors);
for error in errors {
if error.obligation.predicate == self.predicate {
// Save the cause from the greatest depth - this corresponds
// to picking more-specific types (e.g. `MyStruct<u8>`)
// over less-specific types (e.g. `Option<MyStruct<u8>>`)
if self.depth >= self.cause_depth {
self.cause = Some(error.obligation.cause);
self.cause_depth = self.depth
}

ocx.register_obligation(traits::Obligation::new(
self.tcx,
cause,
self.param_env,
ty::PredicateKind::WellFormed(tcx_ty.into()),
));

for error in ocx.select_all_or_error() {
debug!("Wf-check got error for {:?}: {:?}", ty, error);
if error.obligation.predicate == self.predicate {
// Save the cause from the greatest depth - this corresponds
// to picking more-specific types (e.g. `MyStruct<u8>`)
// over less-specific types (e.g. `Option<MyStruct<u8>>`)
if self.depth >= self.cause_depth {
self.cause = Some(error.obligation.cause);
self.cause_depth = self.depth
}
}
}

self.depth += 1;
intravisit::walk_ty(self, ty);
self.depth -= 1;
Expand Down
33 changes: 16 additions & 17 deletions compiler/rustc_hir_analysis/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ use rustc_errors::ErrorGuaranteed;
use rustc_errors::{DiagnosticMessage, SubdiagnosticMessage};
use rustc_hir as hir;
use rustc_hir::Node;
use rustc_infer::infer::{DefineOpaqueTypes, InferOk, TyCtxtInferExt};
use rustc_infer::infer::TyCtxtInferExt;
use rustc_macros::fluent_messages;
use rustc_middle::middle;
use rustc_middle::ty::query::Providers;
Expand All @@ -113,7 +113,7 @@ use rustc_span::def_id::{DefId, LocalDefId, CRATE_DEF_ID};
use rustc_span::{symbol::sym, Span, DUMMY_SP};
use rustc_target::spec::abi::Abi;
use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt as _;
use rustc_trait_selection::traits::{self, ObligationCause, ObligationCauseCode};
use rustc_trait_selection::traits::{self, ObligationCause, ObligationCauseCode, ObligationCtxt};

use std::ops::Not;

Expand Down Expand Up @@ -160,24 +160,21 @@ fn require_c_abi_if_c_variadic(tcx: TyCtxt<'_>, decl: &hir::FnDecl<'_>, abi: Abi
fn require_same_types<'tcx>(
tcx: TyCtxt<'tcx>,
cause: &ObligationCause<'tcx>,
param_env: ty::ParamEnv<'tcx>,
expected: Ty<'tcx>,
actual: Ty<'tcx>,
) -> bool {
) {
let infcx = &tcx.infer_ctxt().build();
let param_env = ty::ParamEnv::empty();
let errors = match infcx.at(cause, param_env).eq(DefineOpaqueTypes::No, expected, actual) {
Ok(InferOk { obligations, .. }) => traits::fully_solve_obligations(infcx, obligations),
let ocx = ObligationCtxt::new(infcx);
match ocx.eq(cause, param_env, expected, actual) {
Ok(()) => {
let errors = ocx.select_all_or_error();
if !errors.is_empty() {
infcx.err_ctxt().report_fulfillment_errors(&errors);
}
}
Err(err) => {
infcx.err_ctxt().report_mismatched_types(cause, expected, actual, err).emit();
return false;
}
};

match &errors[..] {
[] => true,
errors => {
infcx.err_ctxt().report_fulfillment_errors(errors);
false
}
}
}
Expand Down Expand Up @@ -296,6 +293,8 @@ fn check_main_fn_ty(tcx: TyCtxt<'_>, main_def_id: DefId) {
return;
}

// Main should have no WC, so empty param env is OK here.
let param_env = ty::ParamEnv::empty();
let expected_return_type;
if let Some(term_did) = tcx.lang_items().termination() {
let return_ty = main_fnsig.output();
Expand All @@ -306,8 +305,6 @@ fn check_main_fn_ty(tcx: TyCtxt<'_>, main_def_id: DefId) {
}
let return_ty = return_ty.skip_binder();
let infcx = tcx.infer_ctxt().build();
// Main should have no WC, so empty param env is OK here.
let param_env = ty::ParamEnv::empty();
let cause = traits::ObligationCause::new(
return_ty_span,
main_diagnostics_def_id,
Expand Down Expand Up @@ -343,6 +340,7 @@ fn check_main_fn_ty(tcx: TyCtxt<'_>, main_def_id: DefId) {
main_diagnostics_def_id,
ObligationCauseCode::MainFunctionType,
),
param_env,
se_ty,
tcx.mk_fn_ptr(main_fnsig),
);
Expand Down Expand Up @@ -417,6 +415,7 @@ fn check_start_fn_ty(tcx: TyCtxt<'_>, start_def_id: DefId) {
start_def_id,
ObligationCauseCode::StartFunctionType,
),
ty::ParamEnv::empty(), // start should not have any where bounds.
se_ty,
tcx.mk_fn_ptr(tcx.fn_sig(start_def_id).subst_identity()),
);
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_hir_typeck/src/callee.rs
Original file line number Diff line number Diff line change
Expand Up @@ -668,7 +668,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {

if !self.maybe_suggest_bad_array_definition(&mut err, call_expr, callee_expr) {
if let Some((maybe_def, output_ty, _)) = self.extract_callable_info(callee_ty)
&& !self.type_is_sized_modulo_regions(self.param_env, output_ty, callee_expr.span)
&& !self.type_is_sized_modulo_regions(self.param_env, output_ty)
{
let descr = match maybe_def {
DefIdOrName::DefId(def_id) => self.tcx.def_descr(def_id),
Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_hir_typeck/src/cast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let t = self.resolve_vars_if_possible(t);
t.error_reported()?;

if self.type_is_sized_modulo_regions(self.param_env, t, span) {
if self.type_is_sized_modulo_regions(self.param_env, t) {
return Ok(Some(PointerKind::Thin));
}

Expand Down Expand Up @@ -722,7 +722,7 @@ impl<'a, 'tcx> CastCheck<'tcx> {

debug!("check_cast({}, {:?} as {:?})", self.expr.hir_id, self.expr_ty, self.cast_ty);

if !fcx.type_is_sized_modulo_regions(fcx.param_env, self.cast_ty, self.span)
if !fcx.type_is_sized_modulo_regions(fcx.param_env, self.cast_ty)
&& !self.cast_ty.has_infer_types()
{
self.report_cast_to_unsized_type(fcx);
Expand Down
16 changes: 7 additions & 9 deletions compiler/rustc_hir_typeck/src/coercion.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ use rustc_hir::Expr;
use rustc_hir_analysis::astconv::AstConv;
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
use rustc_infer::infer::{Coercion, DefineOpaqueTypes, InferOk, InferResult};
use rustc_infer::traits::Obligation;
use rustc_infer::traits::{Obligation, PredicateObligation};
use rustc_middle::lint::in_external_macro;
use rustc_middle::ty::adjustment::{
Adjust, Adjustment, AllowTwoPhase, AutoBorrow, AutoBorrowMutability, PointerCast,
Expand Down Expand Up @@ -597,13 +597,11 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
// and almost never more than 3. By using a SmallVec we avoid an
// allocation, at the (very small) cost of (occasionally) having to
// shift subsequent elements down when removing the front element.
let mut queue: SmallVec<[_; 4]> = smallvec![traits::predicate_for_trait_def(
let mut queue: SmallVec<[PredicateObligation<'tcx>; 4]> = smallvec![Obligation::new(
self.tcx,
self.fcx.param_env,
cause,
coerce_unsized_did,
0,
[coerce_source, coerce_target]
self.fcx.param_env,
self.tcx.mk_trait_ref(coerce_unsized_did, [coerce_source, coerce_target])
)];

let mut has_unsized_tuple_coercion = false;
Expand Down Expand Up @@ -651,9 +649,9 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
let self_ty = trait_pred.skip_binder().self_ty();
let unsize_ty = trait_pred.skip_binder().trait_ref.substs[1].expect_ty();
debug!("coerce_unsized: ambiguous unsize case for {:?}", trait_pred);
match (&self_ty.kind(), &unsize_ty.kind()) {
(ty::Infer(ty::TyVar(v)), ty::Dynamic(..))
if self.type_var_is_sized(*v) =>
match (self_ty.kind(), unsize_ty.kind()) {
(&ty::Infer(ty::TyVar(v)), ty::Dynamic(..))
if self.type_var_is_sized(v) =>
{
debug!("coerce_unsized: have sized infer {:?}", v);
coercion.obligations.push(obligation);
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_hir_typeck/src/demand.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1480,7 +1480,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {

// For this suggestion to make sense, the type would need to be `Copy`,
// or we have to be moving out of a `Box<T>`
if self.type_is_copy_modulo_regions(self.param_env, expected, sp)
if self.type_is_copy_modulo_regions(self.param_env, expected)
// FIXME(compiler-errors): We can actually do this if the checked_ty is
// `steps` layers of boxes, not just one, but this is easier and most likely.
|| (checked_ty.is_box() && steps == 1)
Expand Down
5 changes: 1 addition & 4 deletions compiler/rustc_hir_typeck/src/expr_use_visitor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -867,10 +867,7 @@ fn copy_or_move<'a, 'tcx>(
mc: &mc::MemCategorizationContext<'a, 'tcx>,
place_with_id: &PlaceWithHirId<'tcx>,
) -> ConsumeMode {
if !mc.type_is_copy_modulo_regions(
place_with_id.place.ty(),
mc.tcx().hir().span(place_with_id.hir_id),
) {
if !mc.type_is_copy_modulo_regions(place_with_id.place.ty()) {
ConsumeMode::Move
} else {
ConsumeMode::Copy
Expand Down
9 changes: 4 additions & 5 deletions compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1011,11 +1011,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let mut suggest_copied_or_cloned = || {
let expr_inner_ty = substs.type_at(0);
let expected_inner_ty = expected_substs.type_at(0);
if let ty::Ref(_, ty, hir::Mutability::Not) = expr_inner_ty.kind()
&& self.can_eq(self.param_env, *ty, expected_inner_ty)
if let &ty::Ref(_, ty, hir::Mutability::Not) = expr_inner_ty.kind()
&& self.can_eq(self.param_env, ty, expected_inner_ty)
{
let def_path = self.tcx.def_path_str(adt_def.did());
if self.type_is_copy_modulo_regions(self.param_env, *ty, expr.span) {
if self.type_is_copy_modulo_regions(self.param_env, ty) {
diag.span_suggestion_verbose(
expr.span.shrink_to_hi(),
format!(
Expand All @@ -1029,9 +1029,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
&& rustc_trait_selection::traits::type_known_to_meet_bound_modulo_regions(
self,
self.param_env,
*ty,
ty,
clone_did,
expr.span
)
{
diag.span_suggestion_verbose(
Expand Down
Loading

0 comments on commit 9bdb488

Please sign in to comment.