Skip to content
Open
Show file tree
Hide file tree
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
12 changes: 11 additions & 1 deletion compiler/rustc_const_eval/src/const_eval/machine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ use crate::interpret::{
self, AllocId, AllocInit, AllocRange, ConstAllocation, CtfeProvenance, FnArg, Frame,
GlobalAlloc, ImmTy, InterpCx, InterpResult, OpTy, PlaceTy, RangeSet, Scalar,
compile_time_machine, err_inval, interp_ok, throw_exhaust, throw_inval, throw_ub,
throw_ub_custom, throw_unsup, throw_unsup_format,
throw_ub_custom, throw_unsup, throw_unsup_format, type_implements_dyn_trait,
};

/// When hitting this many interpreted terminators we emit a deny by default lint
Expand Down Expand Up @@ -586,6 +586,16 @@ impl<'tcx> interpret::Machine<'tcx> for CompileTimeMachine<'tcx> {
}
}

sym::type_id_implements_trait => {
let type_from_type_id = ecx.read_type_id(&args[0])?;
let trait_from_type_id = ecx.read_type_id(&args[1])?;

let (implements, _) =
type_implements_dyn_trait(ecx, type_from_type_id, trait_from_type_id)?;

ecx.write_scalar(Scalar::from_bool(implements), dest)?;
}

sym::type_of => {
let ty = ecx.read_type_id(&args[0])?;
ecx.write_type_info(ty, dest)?;
Expand Down
3 changes: 3 additions & 0 deletions compiler/rustc_const_eval/src/const_eval/type_info.rs
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,9 @@ impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> {
};
self.write_discriminant(variant_index, &field_dest)?;
}
sym::id => {
self.write_type_id(ty, &field_dest)?;
}
other => span_bug!(self.tcx.span, "unknown `Type` field {other}"),
}
}
Expand Down
33 changes: 4 additions & 29 deletions compiler/rustc_const_eval/src/interpret/intrinsics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,12 @@ mod simd;
use rustc_abi::{FIRST_VARIANT, FieldIdx, HasDataLayout, Size, VariantIdx};
use rustc_apfloat::ieee::{Double, Half, Quad, Single};
use rustc_data_structures::assert_matches;
use rustc_hir::def_id::CRATE_DEF_ID;
use rustc_infer::infer::TyCtxtInferExt;
use rustc_middle::mir::interpret::{CTFE_ALLOC_SALT, read_target_uint, write_target_uint};
use rustc_middle::mir::{self, BinOp, ConstValue, NonDivergingIntrinsic};
use rustc_middle::ty::layout::TyAndLayout;
use rustc_middle::ty::{FloatTy, PolyExistentialPredicate, Ty, TyCtxt};
use rustc_middle::ty::{FloatTy, Ty, TyCtxt};
use rustc_middle::{bug, span_bug, ty};
use rustc_span::{Symbol, sym};
use rustc_trait_selection::traits::{Obligation, ObligationCause, ObligationCtxt};
use tracing::trace;

use super::memory::MemoryKind;
Expand All @@ -27,6 +24,7 @@ use super::{
};
use crate::fluent_generated as fluent;
use crate::interpret::Writeable;
use crate::interpret::util::type_implements_dyn_trait;

#[derive(Copy, Clone, Debug, PartialEq, Eq)]
enum MulAddType {
Expand Down Expand Up @@ -226,32 +224,9 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
let tp_ty = instance.args.type_at(0);
let result_ty = instance.args.type_at(1);

ensure_monomorphic_enough(tcx, tp_ty)?;
ensure_monomorphic_enough(tcx, result_ty)?;
let ty::Dynamic(preds, _) = result_ty.kind() else {
span_bug!(
self.find_closest_untracked_caller_location(),
"Invalid type provided to vtable_for::<T, U>. U must be dyn Trait, got {result_ty}."
);
};
let (implements_trait, preds) = type_implements_dyn_trait(self, tp_ty, result_ty)?;

let (infcx, param_env) =
self.tcx.infer_ctxt().build_with_typing_env(self.typing_env);

let ocx = ObligationCtxt::new(&infcx);
ocx.register_obligations(preds.iter().map(|pred: PolyExistentialPredicate<'_>| {
let pred = pred.with_self_ty(tcx, tp_ty);
// Lifetimes can only be 'static because of the bound on T
let pred = ty::fold_regions(tcx, pred, |r, _| {
if r == tcx.lifetimes.re_erased { tcx.lifetimes.re_static } else { r }
});
Obligation::new(tcx, ObligationCause::dummy(), param_env, pred)
}));
let type_impls_trait = ocx.evaluate_obligations_error_on_ambiguity().is_empty();
// Since `assumed_wf_tys=[]` the choice of LocalDefId is irrelevant, so using the "default"
let regions_are_valid = ocx.resolve_regions(CRATE_DEF_ID, param_env, []).is_empty();

if regions_are_valid && type_impls_trait {
if implements_trait {
let vtable_ptr = self.get_vtable_ptr(tp_ty, preds)?;
// Writing a non-null pointer into an `Option<NonNull>` will automatically make it `Some`.
self.write_pointer(vtable_ptr, dest)?;
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_const_eval/src/interpret/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,6 @@ use self::place::{MemPlace, Place};
pub use self::projection::{OffsetMode, Projectable};
pub use self::stack::{Frame, FrameInfo, LocalState, ReturnContinuation, StackPopInfo};
pub use self::util::EnteredTraceSpan;
pub(crate) use self::util::create_static_alloc;
pub(crate) use self::util::{create_static_alloc, type_implements_dyn_trait};
pub use self::validity::{CtfeValidationMode, RangeSet, RefTracking};
pub use self::visitor::ValueVisitor;
45 changes: 42 additions & 3 deletions compiler/rustc_const_eval/src/interpret/util.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,51 @@
use rustc_hir::def_id::LocalDefId;
use rustc_middle::mir;
use rustc_hir::def_id::{CRATE_DEF_ID, LocalDefId};
use rustc_infer::infer::TyCtxtInferExt;
use rustc_infer::traits::{Obligation, ObligationCause};
use rustc_middle::mir::interpret::{AllocInit, Allocation, GlobalAlloc, InterpResult, Pointer};
use rustc_middle::ty::layout::TyAndLayout;
use rustc_middle::ty::{TyCtxt, TypeVisitable, TypeVisitableExt};
use rustc_middle::ty::{PolyExistentialPredicate, Ty, TyCtxt, TypeVisitable, TypeVisitableExt};
use rustc_middle::{mir, span_bug, ty};
use rustc_trait_selection::traits::ObligationCtxt;
use tracing::debug;

use super::{InterpCx, MPlaceTy, MemoryKind, interp_ok, throw_inval};
use crate::const_eval::{CompileTimeInterpCx, CompileTimeMachine, InterpretationResult};
use crate::interpret::Machine;

/// Checks if a type implements predicates.
/// Calls `ensure_monomorphic_enough` on `ty` and `trait_ty` for you.
pub(crate) fn type_implements_dyn_trait<'tcx, M: Machine<'tcx>>(
ecx: &mut InterpCx<'tcx, M>,
ty: Ty<'tcx>,
trait_ty: Ty<'tcx>,
) -> InterpResult<'tcx, (bool, &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>)> {
ensure_monomorphic_enough(ecx.tcx.tcx, ty)?;
ensure_monomorphic_enough(ecx.tcx.tcx, trait_ty)?;

let ty::Dynamic(preds, _) = trait_ty.kind() else {
span_bug!(
ecx.find_closest_untracked_caller_location(),
"Invalid type provided to type_implements_predicates. U must be dyn Trait, got {trait_ty}."
);
};

let (infcx, param_env) = ecx.tcx.infer_ctxt().build_with_typing_env(ecx.typing_env);

let ocx = ObligationCtxt::new(&infcx);
ocx.register_obligations(preds.iter().map(|pred: PolyExistentialPredicate<'_>| {
let pred = pred.with_self_ty(ecx.tcx.tcx, ty);
// Lifetimes can only be 'static because of the bound on T
let pred = rustc_middle::ty::fold_regions(ecx.tcx.tcx, pred, |r, _| {
if r == ecx.tcx.tcx.lifetimes.re_erased { ecx.tcx.tcx.lifetimes.re_static } else { r }
});
Obligation::new(ecx.tcx.tcx, ObligationCause::dummy(), param_env, pred)
}));
let type_impls_trait = ocx.evaluate_obligations_error_on_ambiguity().is_empty();
// Since `assumed_wf_tys=[]` the choice of LocalDefId is irrelevant, so using the "default"
let regions_are_valid = ocx.resolve_regions(CRATE_DEF_ID, param_env, []).is_empty();

interp_ok((regions_are_valid && type_impls_trait, preds))
}

/// Checks whether a type contains generic parameters which must be instantiated.
///
Expand Down
7 changes: 7 additions & 0 deletions compiler/rustc_hir_analysis/src/check/intrinsic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,7 @@ fn intrinsic_operation_unsafety(tcx: TyCtxt<'_>, intrinsic_id: LocalDefId) -> hi
| sym::truncf128
| sym::type_id
| sym::type_id_eq
| sym::type_id_implements_trait
| sym::type_name
| sym::type_of
| sym::ub_checks
Expand Down Expand Up @@ -322,6 +323,12 @@ pub(crate) fn check_intrinsic_type(
let type_id = tcx.type_of(tcx.lang_items().type_id().unwrap()).no_bound_vars().unwrap();
(0, 0, vec![type_id, type_id], tcx.types.bool)
}
sym::type_id_implements_trait => (
0,
0,
vec![tcx.type_of(tcx.lang_items().type_id().unwrap()).no_bound_vars().unwrap(); 2],
tcx.types.bool,
),
sym::type_of => (
0,
0,
Expand Down
2 changes: 2 additions & 0 deletions compiler/rustc_span/src/symbol.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1239,6 +1239,7 @@ symbols! {
i128_legacy_fn_min_value,
i128_legacy_mod,
i128_type,
id,
ident,
if_let,
if_let_guard,
Expand Down Expand Up @@ -2339,6 +2340,7 @@ symbols! {
type_const,
type_id,
type_id_eq,
type_id_implements_trait,
type_info,
type_ir,
type_ir_infer_ctxt_like,
Expand Down
9 changes: 9 additions & 0 deletions library/core/src/intrinsics/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2852,6 +2852,15 @@ pub const unsafe fn size_of_val<T: ?Sized>(ptr: *const T) -> usize;
#[rustc_intrinsic_const_stable_indirect]
pub const unsafe fn align_of_val<T: ?Sized>(ptr: *const T) -> usize;

/// Check if a type represented by a `TypeId` implements a trait represented by a `TypeId`.
/// It can only be called at compile time, the backends do
/// not implement it.
#[rustc_intrinsic]
#[unstable(feature = "core_intrinsics", issue = "none")]
pub const fn type_id_implements_trait(_id: crate::any::TypeId, _trait: crate::any::TypeId) -> bool {
panic!("`TypeId::implements_trait` can only be called at compile-time")
}

/// Compute the type information of a concrete type.
/// It can only be called at compile time, the backends do
/// not implement it.
Expand Down
29 changes: 28 additions & 1 deletion library/core/src/mem/type_info.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@
//! runtime or const-eval processable way.

use crate::any::TypeId;
use crate::intrinsics::type_of;
use crate::intrinsics::{type_id_implements_trait, type_of};
use crate::ptr;

/// Compile-time type information.
#[derive(Debug)]
Expand All @@ -14,6 +15,8 @@ pub struct Type {
pub kind: TypeKind,
/// Size of the type. `None` if it is unsized
pub size: Option<usize>,
/// `TypeId` that the type was gathered from.
pub id: TypeId,
}

impl TypeId {
Expand All @@ -34,6 +37,30 @@ impl Type {
pub const fn of<T: ?Sized + 'static>() -> Self {
const { TypeId::of::<T>().info() }
}

/// Checks if the type has the trait.
/// It can only be called at compile time.
pub const fn has_trait<T: ptr::Pointee<Metadata = ptr::DynMetadata<T>> + ?Sized + 'static>(
self,
) -> bool {
type_id_implements_trait(self.id, TypeId::of::<T>())
}

/// Checks if the type has the trait represented by the `TypeId`.
/// Returns `None` if the `trait_represented_by_type_id` is not a trait represented by type id.
/// It can only be called at compile time.
#[unstable(feature = "type_info", issue = "146922")]
#[rustc_const_unstable(feature = "type_info", issue = "146922")]
pub const fn has_trait_represented_by_type_id(
self,
trait_represented_by_type_id: TypeId,
) -> Option<bool> {
if matches!(trait_represented_by_type_id.info().kind, TypeKind::DynTrait(_)) {
Some(type_id_implements_trait(self.id, trait_represented_by_type_id))
} else {
None
}
}
}

/// Compile-time type information.
Expand Down
13 changes: 13 additions & 0 deletions library/coretests/tests/mem/type_info.rs
Original file line number Diff line number Diff line change
Expand Up @@ -292,3 +292,16 @@ fn test_dynamic_traits() {
assert!(sync.trait_ty.is_auto);
}
}

#[test]
fn test_implements_trait() {
struct Garlic;
trait Blah {}
impl Blah for Garlic {}

const {
assert!(TypeId::of::<Garlic>().info().has_trait::<dyn Blah>());
assert!(TypeId::of::<Garlic>().info().has_trait::<dyn Blah + Send>());
assert!(!TypeId::of::<*const Box<Garlic>>().info().has_trait::<dyn Sync>());
}
}
2 changes: 1 addition & 1 deletion src/llvm-project
2 changes: 1 addition & 1 deletion src/tools/cargo
Submodule cargo updated 50 files
+1 −1 .github/workflows/main.yml
+2 −9 Cargo.lock
+2 −4 Cargo.toml
+1 −1 crates/cargo-util-schemas/Cargo.toml
+1 −1 crates/cargo-util-schemas/src/manifest/mod.rs
+4 −5 src/bin/cargo/commands/remove.rs
+5 −1 src/cargo/core/compiler/build_runner/compilation_files.rs
+3 −1 src/cargo/core/compiler/job_queue/mod.rs
+2 −6 src/cargo/core/compiler/layout.rs
+4 −3 src/cargo/core/compiler/mod.rs
+236 −55 src/cargo/core/compiler/timings/mod.rs
+48 −0 src/cargo/core/compiler/timings/report.rs
+1 −5 src/cargo/core/compiler/unit_dependencies.rs
+2 −2 src/cargo/core/dependency.rs
+1 −1 src/cargo/core/package.rs
+38 −35 src/cargo/core/registry.rs
+1 −43 src/cargo/core/shell.rs
+0 −9 src/cargo/core/workspace.rs
+23 −68 src/cargo/lints/mod.rs
+4 −19 src/cargo/lints/rules/implicit_minimum_version_req.rs
+0 −3 src/cargo/lints/rules/mod.rs
+0 −262 src/cargo/lints/rules/non_kebab_case_bin.rs
+2 −3 src/cargo/ops/cargo_add/mod.rs
+4 −18 src/cargo/ops/cargo_compile/mod.rs
+1 −5 src/cargo/ops/cargo_compile/unit_generator.rs
+1 −55 src/cargo/ops/cargo_remove.rs
+17 −17 src/cargo/ops/cargo_report/timings.rs
+1 −1 src/cargo/ops/mod.rs
+3 −3 src/cargo/util/log_message.rs
+45 −101 src/cargo/util/logger.rs
+43 −57 src/cargo/util/toml_mut/manifest.rs
+25 −158 src/doc/src/CHANGELOG.md
+0 −37 src/doc/src/reference/lints.md
+2 −2 src/doc/src/reference/semver.md
+2 −1 tests/build-std/main.rs
+0 −98 tests/testsuite/build_dir.rs
+0 −98 tests/testsuite/build_dir_legacy.rs
+1 −1 tests/testsuite/cache_lock.rs
+5 −7 tests/testsuite/cargo_remove/invalid_package_multiple/stderr.term.svg
+0 −14 tests/testsuite/cargo_remove/invalid_section_missing_flags/in/Cargo.toml
+0 −29 tests/testsuite/cargo_remove/invalid_section_missing_flags/mod.rs
+0 −14 tests/testsuite/cargo_remove/invalid_section_missing_flags/out/Cargo.toml
+0 −34 tests/testsuite/cargo_remove/invalid_section_missing_flags/stderr.term.svg
+0 −1 tests/testsuite/cargo_remove/mod.rs
+1 −36 tests/testsuite/features.rs
+33 −20 tests/testsuite/lints/implicit_minimum_version_req.rs
+0 −1 tests/testsuite/lints/mod.rs
+0 −173 tests/testsuite/lints/non_kebab_case_bin.rs
+63 −84 tests/testsuite/patch.rs
+43 −63 tests/testsuite/profile_trim_paths.rs
Loading
Loading