Skip to content

Rollup of 4 pull requests #112471

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 13 commits into from
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
150 changes: 77 additions & 73 deletions compiler/rustc_borrowck/src/region_infer/opaque_types.rs
Original file line number Diff line number Diff line change
@@ -61,7 +61,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
pub(crate) fn infer_opaque_types(
&self,
infcx: &InferCtxt<'tcx>,
opaque_ty_decls: FxIndexMap<OpaqueTypeKey<'tcx>, (OpaqueHiddenType<'tcx>, OpaqueTyOrigin)>,
opaque_ty_decls: FxIndexMap<OpaqueTypeKey<'tcx>, OpaqueHiddenType<'tcx>>,
) -> FxIndexMap<LocalDefId, OpaqueHiddenType<'tcx>> {
let mut result: FxIndexMap<LocalDefId, OpaqueHiddenType<'tcx>> = FxIndexMap::default();

@@ -72,7 +72,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
.collect();
debug!(?member_constraints);

for (opaque_type_key, (concrete_type, origin)) in opaque_ty_decls {
for (opaque_type_key, concrete_type) in opaque_ty_decls {
let substs = opaque_type_key.substs;
debug!(?concrete_type, ?substs);

@@ -143,7 +143,6 @@ impl<'tcx> RegionInferenceContext<'tcx> {
let ty = infcx.infer_opaque_definition_from_instantiation(
opaque_type_key,
universal_concrete_type,
origin,
);
// Sometimes two opaque types are the same only after we remap the generic parameters
// back to the opaque type definition. E.g. we may have `OpaqueType<X, Y>` mapped to `(X, Y)`
@@ -215,7 +214,6 @@ pub trait InferCtxtExt<'tcx> {
&self,
opaque_type_key: OpaqueTypeKey<'tcx>,
instantiated_ty: OpaqueHiddenType<'tcx>,
origin: OpaqueTyOrigin,
) -> Ty<'tcx>;
}

@@ -248,109 +246,115 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> {
&self,
opaque_type_key: OpaqueTypeKey<'tcx>,
instantiated_ty: OpaqueHiddenType<'tcx>,
origin: OpaqueTyOrigin,
) -> Ty<'tcx> {
if let Some(e) = self.tainted_by_errors() {
return self.tcx.ty_error(e);
}

if let Err(guar) =
check_opaque_type_parameter_valid(self.tcx, opaque_type_key, instantiated_ty.span)
{
return self.tcx.ty_error(guar);
}

let definition_ty = instantiated_ty
.remap_generic_params_to_declaration_params(opaque_type_key, self.tcx, false)
.ty;

if let Err(guar) = check_opaque_type_parameter_valid(
// `definition_ty` does not live in of the current inference context,
// so lets make sure that we don't accidentally misuse our current `infcx`.
match check_opaque_type_well_formed(
self.tcx,
opaque_type_key,
origin,
self.next_trait_solver(),
opaque_type_key.def_id,
instantiated_ty.span,
definition_ty,
) {
return self.tcx.ty_error(guar);
Ok(hidden_ty) => hidden_ty,
Err(guar) => self.tcx.ty_error(guar),
}
}
}

// Only check this for TAIT. RPIT already supports `tests/ui/impl-trait/nested-return-type2.rs`
// on stable and we'd break that.
let OpaqueTyOrigin::TyAlias { .. } = origin else {
return definition_ty;
};
let def_id = opaque_type_key.def_id;
// This logic duplicates most of `check_opaque_meets_bounds`.
// 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);
// HACK This bubble is required for this tests to pass:
// nested-return-type2-tait2.rs
// nested-return-type2-tait3.rs
// FIXME(-Ztrait-solver=next): We probably should use `DefiningAnchor::Error`
// and prepopulate this `InferCtxt` with known opaque values, rather than
// using the `Bind` anchor here. For now it's fine.
let infcx = self
.tcx
.infer_ctxt()
.with_opaque_type_inference(if self.next_trait_solver() {
DefiningAnchor::Bind(def_id)
} else {
DefiningAnchor::Bubble
})
.build();
let ocx = ObligationCtxt::new(&infcx);
// 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
// hidden type is well formed even without those bounds.
let predicate = ty::Binder::dummy(ty::PredicateKind::WellFormed(definition_ty.into()));

let id_substs = InternalSubsts::identity_for_item(self.tcx, def_id);
/// This logic duplicates most of `check_opaque_meets_bounds`.
/// FIXME(oli-obk): Also do region checks here and then consider removing
/// `check_opaque_meets_bounds` entirely.
fn check_opaque_type_well_formed<'tcx>(
tcx: TyCtxt<'tcx>,
next_trait_solver: bool,
def_id: LocalDefId,
definition_span: Span,
definition_ty: Ty<'tcx>,
) -> Result<Ty<'tcx>, ErrorGuaranteed> {
// Only check this for TAIT. RPIT already supports `tests/ui/impl-trait/nested-return-type2.rs`
// on stable and we'd break that.
let opaque_ty_hir = tcx.hir().expect_item(def_id);
let OpaqueTyOrigin::TyAlias { .. } = opaque_ty_hir.expect_opaque_ty().origin else {
return Ok(definition_ty);
};
let param_env = tcx.param_env(def_id);
// HACK This bubble is required for this tests to pass:
// nested-return-type2-tait2.rs
// nested-return-type2-tait3.rs
// FIXME(-Ztrait-solver=next): We probably should use `DefiningAnchor::Error`
// and prepopulate this `InferCtxt` with known opaque values, rather than
// using the `Bind` anchor here. For now it's fine.
let infcx = tcx
.infer_ctxt()
.with_next_trait_solver(next_trait_solver)
.with_opaque_type_inference(if next_trait_solver {
DefiningAnchor::Bind(def_id)
} else {
DefiningAnchor::Bubble
})
.build();
let ocx = ObligationCtxt::new(&infcx);
let identity_substs = InternalSubsts::identity_for_item(tcx, def_id);

// Require that the hidden type actually fulfills all the bounds of the opaque type, even without
// the bounds that the function supplies.
let opaque_ty = self.tcx.mk_opaque(def_id.to_def_id(), id_substs);
if let Err(err) = ocx.eq(
&ObligationCause::misc(instantiated_ty.span, def_id),
param_env,
opaque_ty,
definition_ty,
) {
// Require that the hidden type actually fulfills all the bounds of the opaque type, even without
// the bounds that the function supplies.
let opaque_ty = tcx.mk_opaque(def_id.to_def_id(), identity_substs);
ocx.eq(&ObligationCause::misc(definition_span, def_id), param_env, opaque_ty, definition_ty)
.map_err(|err| {
infcx
.err_ctxt()
.report_mismatched_types(
&ObligationCause::misc(instantiated_ty.span, def_id),
&ObligationCause::misc(definition_span, def_id),
opaque_ty,
definition_ty,
err,
)
.emit();
}
.emit()
})?;

ocx.register_obligation(Obligation::misc(
infcx.tcx,
instantiated_ty.span,
def_id,
param_env,
predicate,
));
// 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
// hidden type is well formed even without those bounds.
let predicate = ty::Binder::dummy(ty::PredicateKind::WellFormed(definition_ty.into()));
ocx.register_obligation(Obligation::misc(tcx, definition_span, def_id, param_env, predicate));

// Check that all obligations are satisfied by the implementation's
// version.
let errors = ocx.select_all_or_error();
// Check that all obligations are satisfied by the implementation's
// version.
let errors = ocx.select_all_or_error();

// This is still required for many(half of the tests in ui/type-alias-impl-trait)
// tests to pass
let _ = infcx.take_opaque_types();
// This is still required for many(half of the tests in ui/type-alias-impl-trait)
// tests to pass
let _ = infcx.take_opaque_types();

if errors.is_empty() {
definition_ty
} else {
let reported = infcx.err_ctxt().report_fulfillment_errors(&errors);
self.tcx.ty_error(reported)
}
if errors.is_empty() {
Ok(definition_ty)
} else {
Err(infcx.err_ctxt().report_fulfillment_errors(&errors))
}
}

fn check_opaque_type_parameter_valid(
tcx: TyCtxt<'_>,
opaque_type_key: OpaqueTypeKey<'_>,
origin: OpaqueTyOrigin,
span: Span,
) -> Result<(), ErrorGuaranteed> {
match origin {
let opaque_ty_hir = tcx.hir().expect_item(opaque_type_key.def_id);
match opaque_ty_hir.expect_opaque_ty().origin {
// No need to check return position impl trait (RPIT)
// because for type and const parameters they are correct
// by construction: we convert
34 changes: 23 additions & 11 deletions compiler/rustc_borrowck/src/type_check/mod.rs
Original file line number Diff line number Diff line change
@@ -7,7 +7,6 @@ use std::{fmt, iter, mem};

use either::Either;

use hir::OpaqueTyOrigin;
use rustc_data_structures::frozen::Frozen;
use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
use rustc_errors::ErrorGuaranteed;
@@ -28,6 +27,7 @@ use rustc_middle::mir::visit::{NonMutatingUseContext, PlaceContext, Visitor};
use rustc_middle::mir::AssertKind;
use rustc_middle::mir::*;
use rustc_middle::traits::query::NoSolution;
use rustc_middle::traits::ObligationCause;
use rustc_middle::ty::adjustment::PointerCast;
use rustc_middle::ty::cast::CastTy;
use rustc_middle::ty::subst::{SubstsRef, UserSubsts};
@@ -241,7 +241,7 @@ pub(crate) fn type_check<'mir, 'tcx>(
hidden_type.ty = infcx.tcx.ty_error(reported);
}

(opaque_type_key, (hidden_type, decl.origin))
(opaque_type_key, hidden_type)
})
.collect();

@@ -878,8 +878,7 @@ struct BorrowCheckContext<'a, 'tcx> {
pub(crate) struct MirTypeckResults<'tcx> {
pub(crate) constraints: MirTypeckRegionConstraints<'tcx>,
pub(crate) universal_region_relations: Frozen<UniversalRegionRelations<'tcx>>,
pub(crate) opaque_type_values:
FxIndexMap<OpaqueTypeKey<'tcx>, (OpaqueHiddenType<'tcx>, OpaqueTyOrigin)>,
pub(crate) opaque_type_values: FxIndexMap<OpaqueTypeKey<'tcx>, OpaqueHiddenType<'tcx>>,
}

/// A collection of region constraints that must be satisfied for the
@@ -1053,15 +1052,28 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
ConstraintCategory::OpaqueType,
CustomTypeOp::new(
|ocx| {
for (key, hidden_ty) in renumbered_opaques {
ocx.register_infer_ok_obligations(
ocx.infcx.register_hidden_type_in_new_solver(
key,
param_env,
hidden_ty.ty,
)?,
let mut obligations = Vec::new();
for (opaque_type_key, hidden_ty) in renumbered_opaques {
let cause = ObligationCause::dummy();
ocx.infcx.insert_hidden_type(
opaque_type_key,
&cause,
param_env,
hidden_ty.ty,
true,
&mut obligations,
)?;

ocx.infcx.add_item_bounds_for_hidden_type(
opaque_type_key,
cause,
param_env,
hidden_ty.ty,
&mut obligations,
);
}

ocx.register_obligations(obligations);
Ok(())
},
"register pre-defined opaques",
9 changes: 5 additions & 4 deletions compiler/rustc_codegen_cranelift/src/codegen_i128.rs
Original file line number Diff line number Diff line change
@@ -22,8 +22,8 @@ pub(crate) fn maybe_codegen<'tcx>(

match bin_op {
BinOp::BitAnd | BinOp::BitOr | BinOp::BitXor => None,
BinOp::Add | BinOp::Sub => None,
BinOp::Mul => {
BinOp::Add | BinOp::AddUnchecked | BinOp::Sub | BinOp::SubUnchecked => None,
BinOp::Mul | BinOp::MulUnchecked => {
let args = [lhs.load_scalar(fx), rhs.load_scalar(fx)];
let ret_val = fx.lib_call(
"__multi3",
@@ -69,7 +69,7 @@ pub(crate) fn maybe_codegen<'tcx>(
}
}
BinOp::Lt | BinOp::Le | BinOp::Eq | BinOp::Ge | BinOp::Gt | BinOp::Ne => None,
BinOp::Shl | BinOp::Shr => None,
BinOp::Shl | BinOp::ShlUnchecked | BinOp::Shr | BinOp::ShrUnchecked => None,
}
}

@@ -131,9 +131,10 @@ pub(crate) fn maybe_codegen_checked<'tcx>(
fx.lib_call(name, param_types, vec![], &args);
Some(out_place.to_cvalue(fx))
}
BinOp::AddUnchecked | BinOp::SubUnchecked | BinOp::MulUnchecked => unreachable!(),
BinOp::Offset => unreachable!("offset should only be used on pointers, not 128bit ints"),
BinOp::Div | BinOp::Rem => unreachable!(),
BinOp::Lt | BinOp::Le | BinOp::Eq | BinOp::Ge | BinOp::Gt | BinOp::Ne => unreachable!(),
BinOp::Shl | BinOp::Shr => unreachable!(),
BinOp::Shl | BinOp::ShlUnchecked | BinOp::Shr | BinOp::ShrUnchecked => unreachable!(),
}
}
20 changes: 3 additions & 17 deletions compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs
Original file line number Diff line number Diff line change
@@ -472,25 +472,11 @@ fn codegen_regular_intrinsic_call<'tcx>(
ret.write_cvalue(fx, CValue::by_val(align, usize_layout));
}

sym::unchecked_add
| sym::unchecked_sub
| sym::unchecked_mul
| sym::exact_div
| sym::unchecked_shl
| sym::unchecked_shr => {
sym::exact_div => {
intrinsic_args!(fx, args => (x, y); intrinsic);

// FIXME trap on overflow
let bin_op = match intrinsic {
sym::unchecked_add => BinOp::Add,
sym::unchecked_sub => BinOp::Sub,
sym::unchecked_mul => BinOp::Mul,
sym::exact_div => BinOp::Div,
sym::unchecked_shl => BinOp::Shl,
sym::unchecked_shr => BinOp::Shr,
_ => unreachable!(),
};
let res = crate::num::codegen_int_binop(fx, bin_op, x, y);
// FIXME trap on inexact
let res = crate::num::codegen_int_binop(fx, BinOp::Div, x, y);
ret.write_cvalue(fx, res);
}
sym::saturating_add | sym::saturating_sub => {
16 changes: 10 additions & 6 deletions compiler/rustc_codegen_cranelift/src/num.rs
Original file line number Diff line number Diff line change
@@ -128,10 +128,11 @@ pub(crate) fn codegen_int_binop<'tcx>(
let rhs = in_rhs.load_scalar(fx);

let b = fx.bcx.ins();
// FIXME trap on overflow for the Unchecked versions
let val = match bin_op {
BinOp::Add => b.iadd(lhs, rhs),
BinOp::Sub => b.isub(lhs, rhs),
BinOp::Mul => b.imul(lhs, rhs),
BinOp::Add | BinOp::AddUnchecked => b.iadd(lhs, rhs),
BinOp::Sub | BinOp::SubUnchecked => b.isub(lhs, rhs),
BinOp::Mul | BinOp::MulUnchecked => b.imul(lhs, rhs),
BinOp::Div => {
if signed {
b.sdiv(lhs, rhs)
@@ -149,16 +150,19 @@ pub(crate) fn codegen_int_binop<'tcx>(
BinOp::BitXor => b.bxor(lhs, rhs),
BinOp::BitAnd => b.band(lhs, rhs),
BinOp::BitOr => b.bor(lhs, rhs),
BinOp::Shl => b.ishl(lhs, rhs),
BinOp::Shr => {
BinOp::Shl | BinOp::ShlUnchecked => b.ishl(lhs, rhs),
BinOp::Shr | BinOp::ShrUnchecked => {
if signed {
b.sshr(lhs, rhs)
} else {
b.ushr(lhs, rhs)
}
}
BinOp::Offset => unreachable!("Offset is not an integer operation"),
// Compare binops handles by `codegen_binop`.
_ => unreachable!("{:?}({:?}, {:?})", bin_op, in_lhs.layout().ty, in_rhs.layout().ty),
BinOp::Eq | BinOp::Ne | BinOp::Lt | BinOp::Le | BinOp::Gt | BinOp::Ge => {
unreachable!("{:?}({:?}, {:?})", bin_op, in_lhs.layout().ty, in_rhs.layout().ty);
}
};

CValue::by_val(val, in_lhs.layout())
Loading