Skip to content
Merged
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
28 changes: 26 additions & 2 deletions compiler/rustc_hir_analysis/src/check/check.rs
Original file line number Diff line number Diff line change
Expand Up @@ -952,10 +952,10 @@ pub(crate) fn check_item_type(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Result<(),
tcx.ensure_ok().type_of(def_id);
tcx.ensure_ok().predicates_of(def_id);
check_type_alias_type_params_are_used(tcx, def_id);
let ty = tcx.type_of(def_id).instantiate_identity();
let span = tcx.def_span(def_id);
if tcx.type_alias_is_lazy(def_id) {
res = res.and(enter_wf_checking_ctxt(tcx, def_id, |wfcx| {
let ty = tcx.type_of(def_id).instantiate_identity();
let span = tcx.def_span(def_id);
let item_ty = wfcx.deeply_normalize(span, Some(WellFormedLoc::Ty(def_id)), ty);
wfcx.register_wf_obligation(
span,
Expand All @@ -966,6 +966,30 @@ pub(crate) fn check_item_type(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Result<(),
Ok(())
}));
check_variances_for_type_defn(tcx, def_id);
} else {
res = res.and(enter_wf_checking_ctxt(tcx, def_id, |wfcx| {
// HACK: We sometimes incidentally check that const arguments have the correct
// type as a side effect of the anon const desugaring. To make this "consistent"
// for users we explicitly check `ConstArgHasType` clauses so that const args
// that don't go through an anon const still have their types checked.
//
// We use the unnormalized type as this mirrors the behaviour that we previously
// would have had when all const arguments were anon consts.
//
// Changing this to normalized obligations is a breaking change:
// `type Bar = [(); panic!()];` would become an error
if let Some(unnormalized_obligations) = wfcx.unnormalized_obligations(span, ty)
{
let filtered_obligations =
unnormalized_obligations.into_iter().filter(|o| {
matches!(o.predicate.kind().skip_binder(),
ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(ct, _))
if matches!(ct.kind(), ty::ConstKind::Param(..)))
});
wfcx.ocx.register_obligations(filtered_obligations)
}
Ok(())
}));
}

// Only `Node::Item` and `Node::ForeignItem` still have HIR based
Expand Down
22 changes: 21 additions & 1 deletion compiler/rustc_hir_analysis/src/check/wfcheck.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ use rustc_hir::lang_items::LangItem;
use rustc_hir::{AmbigArg, ItemKind, find_attr};
use rustc_infer::infer::outlives::env::OutlivesEnvironment;
use rustc_infer::infer::{self, InferCtxt, SubregionOrigin, TyCtxtInferExt};
use rustc_infer::traits::PredicateObligations;
use rustc_lint_defs::builtin::SHADOWING_SUPERTRAIT_ITEMS;
use rustc_macros::Diagnostic;
use rustc_middle::mir::interpret::ErrorHandled;
Expand Down Expand Up @@ -124,6 +125,20 @@ impl<'tcx> WfCheckingCtxt<'_, 'tcx> {
ty::ClauseKind::WellFormed(term),
));
}

pub(super) fn unnormalized_obligations(
&self,
span: Span,
ty: Ty<'tcx>,
) -> Option<PredicateObligations<'tcx>> {
traits::wf::unnormalized_obligations(
self.ocx.infcx,
self.param_env,
ty.into(),
span,
self.body_def_id,
)
}
}

pub(super) fn enter_wf_checking_ctxt<'tcx, F>(
Expand All @@ -140,7 +155,12 @@ where

let mut wfcx = WfCheckingCtxt { ocx, body_def_id, param_env };

if !tcx.features().trivial_bounds() {
// As of now, bounds are only checked on lazy type aliases, they're ignored for most type
// aliases. So, only check for false global bounds if we're not ignoring bounds altogether.
let ignore_bounds =
tcx.def_kind(body_def_id) == DefKind::TyAlias && !tcx.type_alias_is_lazy(body_def_id);

if !ignore_bounds && !tcx.features().trivial_bounds() {
wfcx.check_false_global_bounds()
}
f(&mut wfcx)?;
Expand Down
43 changes: 41 additions & 2 deletions compiler/rustc_trait_selection/src/traits/wf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -942,14 +942,53 @@ impl<'a, 'tcx> TypeVisitor<TyCtxt<'tcx>> for WfPredicates<'a, 'tcx> {
// FIXME(#27579) RFC also considers adding trait
// obligations that don't refer to Self and
// checking those
if let Some(principal) = data.principal_def_id() {
if let Some(principal) = data.principal() {
let principal_def_id = principal.skip_binder().def_id;
self.out.push(traits::Obligation::with_depth(
tcx,
self.cause(ObligationCauseCode::WellFormed(None)),
self.recursion_depth,
self.param_env,
ty::Binder::dummy(ty::PredicateKind::DynCompatible(principal)),
ty::Binder::dummy(ty::PredicateKind::DynCompatible(principal_def_id)),
));

// For the most part we don't add wf predicates corresponding to
// the trait ref's generic arguments which allows code like this
// to compile:
// ```rust
// trait Trait<T: Sized> {}
// fn foo(_: &dyn Trait<[u32]>) {}
// ```
//
// However, we sometimes incidentally check that const arguments
// have the correct type as a side effect of the anon const
// desugaring. To make this "consistent" for users we explicitly
// check `ConstArgHasType` clauses so that const args that don't
// go through an anon const still have their types checked.
//
// See also: https://rustc-dev-guide.rust-lang.org/const-generics.html
let args = principal.skip_binder().with_self_ty(self.tcx(), t).args;
let obligations =
self.nominal_obligations(principal_def_id, args).into_iter().filter(|o| {
let kind = o.predicate.kind().skip_binder();
match kind {
ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(
ct,
_,
)) if matches!(ct.kind(), ty::ConstKind::Param(..)) => {
// ConstArgHasType clauses are not higher kinded. Assert as
// such so we can fix this up if that ever changes.
assert!(o.predicate.kind().bound_vars().is_empty());
// In stable rust, variables from the trait object binder
// cannot be referenced by a ConstArgHasType clause. However,
// under `generic_const_parameter_types`, it can. Ignore those
// predicates for now, to not have HKT-ConstArgHasTypes.
!kind.has_escaping_bound_vars()
}
_ => false,
}
});
self.out.extend(obligations);
}

if !t.has_escaping_bound_vars() {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
error: the constant `B` is not of type `usize`
--> $DIR/check_const_arg_type_in_free_alias.rs:15:1
|
LL | type ArrLen<const B: bool> = [(); B];
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `usize`, found `bool`
|
= note: the length of array `[(); B]` must be type `usize`

error: the constant `B` is not of type `usize`
--> $DIR/check_const_arg_type_in_free_alias.rs:19:1
|
LL | type ConstArg<const B: bool> = Foo<B>;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `usize`, found `bool`
|
note: required by a const generic parameter in `Foo`
--> $DIR/check_const_arg_type_in_free_alias.rs:13:12
|
LL | struct Foo<const N: usize>;
| ^^^^^^^^^^^^^^ required by this const generic parameter in `Foo`

error: the constant `B` is not of type `usize`
--> $DIR/check_const_arg_type_in_free_alias.rs:32:1
|
LL | type Alias<const B: bool> = <() as IdentityWithUnused<B>>::This;
| ^^^^^^^^^^^^^^^^^^^^^^^^^ expected `usize`, found `bool`
|
note: required by a const generic parameter in `IdentityWithUnused`
--> $DIR/check_const_arg_type_in_free_alias.rs:24:26
|
LL | trait IdentityWithUnused<const N: usize> {
| ^^^^^^^^^^^^^^ required by this const generic parameter in `IdentityWithUnused`

error: the constant `B` is not of type `usize`
--> $DIR/check_const_arg_type_in_free_alias.rs:38:1
|
LL | type UseFree<const B: bool> = Free<B>;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `usize`, found `bool`
|
= note: the length of array `[(); B]` must be type `usize`

error: the constant `B` is not of type `usize`
--> $DIR/check_const_arg_type_in_free_alias.rs:58:1
|
LL | type IndirectArr<const B: bool> = Wrap<Wrap<[(); B]>>;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `usize`, found `bool`
|
= note: the length of array `[(); B]` must be type `usize`

error: the constant `B` is not of type `usize`
--> $DIR/check_const_arg_type_in_free_alias.rs:62:1
|
LL | type IndirectConstArg<const B: bool> = Wrap<Wrap<Foo<B>>>;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `usize`, found `bool`
|
note: required by a const generic parameter in `Foo`
--> $DIR/check_const_arg_type_in_free_alias.rs:13:12
|
LL | struct Foo<const N: usize>;
| ^^^^^^^^^^^^^^ required by this const generic parameter in `Foo`

error[E0308]: mismatched types
--> $DIR/check_const_arg_type_in_free_alias.rs:17:24
|
LL | type AnonArrLen = [(); true];
| ^^^^ expected `usize`, found `bool`
|
= note: array length can only be `usize`

error[E0308]: mismatched types
--> $DIR/check_const_arg_type_in_free_alias.rs:21:25
|
LL | type AnonConstArg = Foo<true>;
| ^^^^ expected `usize`, found `bool`
|
note: expected because of the type of the const parameter
--> $DIR/check_const_arg_type_in_free_alias.rs:13:12
|
LL | struct Foo<const N: usize>;
| ^^^^^^^^^^^^^^

error[E0308]: mismatched types
--> $DIR/check_const_arg_type_in_free_alias.rs:34:44
|
LL | type AnonAlias = <() as IdentityWithUnused<true>>::This;
| ^^^^ expected `usize`, found `bool`

error[E0308]: mismatched types
--> $DIR/check_const_arg_type_in_free_alias.rs:40:25
|
LL | type AnonUseFree = Free<true>;
| ^^^^ expected `usize`, found `bool`
|
note: expected because of the type of the const parameter
--> $DIR/check_const_arg_type_in_free_alias.rs:37:11
|
LL | type Free<const N: usize> = [(); N];
| ^^^^^^^^^^^^^^

error[E0308]: mismatched types
--> $DIR/check_const_arg_type_in_free_alias.rs:53:45
|
LL | type AnonUseFreeIndirectlyCorrect = UseFree<1_usize>;
| ^^^^^^^ expected `bool`, found `usize`
|
note: expected because of the type of the const parameter
--> $DIR/check_const_arg_type_in_free_alias.rs:38:14
|
LL | type UseFree<const B: bool> = Free<B>;
| ^^^^^^^^^^^^^

error[E0308]: mismatched types
--> $DIR/check_const_arg_type_in_free_alias.rs:60:39
|
LL | type AnonIndirectArr = Wrap<Wrap<[(); true]>>;
| ^^^^ expected `usize`, found `bool`
|
= note: array length can only be `usize`

error[E0308]: mismatched types
--> $DIR/check_const_arg_type_in_free_alias.rs:64:43
|
LL | type AnonIndirectConstArg = Wrap<Wrap<Foo<true>>>;
| ^^^^ expected `usize`, found `bool`
|
note: expected because of the type of the const parameter
--> $DIR/check_const_arg_type_in_free_alias.rs:13:12
|
LL | struct Foo<const N: usize>;
| ^^^^^^^^^^^^^^

error: aborting due to 13 previous errors

For more information about this error, try `rustc --explain E0308`.
Loading
Loading