Skip to content
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

[WIP] rustc_typeck: ensure type alias bounds are implied by the type being well-formed. #54090

Closed
wants to merge 3 commits into from
Closed
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
25 changes: 16 additions & 9 deletions src/librustc_typeck/check/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1316,12 +1316,14 @@ pub fn check_item_type<'a,'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, it: &'tcx hir::Item
hir::ItemKind::Union(..) => {
check_union(tcx, it.id, it.span);
}
hir::ItemKind::Existential(..) |
hir::ItemKind::Ty(..) => {
hir::ItemKind::Existential(..)
// HACK(eddyb) This is done in `wfcheck` for type aliases, instead.
// | hir::ItemKind::Ty(..)
=> {
let def_id = tcx.hir.local_def_id(it.id);
let pty_ty = tcx.type_of(def_id);
let generics = tcx.generics_of(def_id);
check_bounds_are_used(tcx, &generics, pty_ty);
let _ = check_params_are_used(tcx, &generics, pty_ty);
}
hir::ItemKind::ForeignMod(ref m) => {
check_abi(tcx, it.span, m.abi);
Expand Down Expand Up @@ -5240,14 +5242,16 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
}
}

pub fn check_bounds_are_used<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
generics: &ty::Generics,
ty: Ty<'tcx>) {
fn check_params_are_used<'a, 'tcx>(
tcx: TyCtxt<'a, 'tcx, 'tcx>,
generics: &ty::Generics,
ty: Ty<'tcx>,
) -> Result<(), ErrorReported> {
let own_counts = generics.own_counts();
debug!("check_bounds_are_used(n_tps={}, ty={:?})", own_counts.types, ty);
debug!("check_params_are_used(n_tps={}, ty={:?})", own_counts.types, ty);

if own_counts.types == 0 {
return;
return Ok(());
}
// Make a vector of booleans initially false, set to true when used.
let mut types_used = vec![false; own_counts.types];
Expand All @@ -5260,23 +5264,26 @@ pub fn check_bounds_are_used<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
// If there is already another error, do not emit
// an error for not using a type Parameter.
assert!(tcx.sess.err_count() > 0);
return;
return Err(ErrorReported);
}
}

let types = generics.params.iter().filter(|param| match param.kind {
ty::GenericParamDefKind::Type { .. } => true,
_ => false,
});
let mut result = Ok(());
for (&used, param) in types_used.iter().zip(types) {
if !used {
let id = tcx.hir.as_local_node_id(param.def_id).unwrap();
let span = tcx.hir.span(id);
struct_span_err!(tcx.sess, span, E0091, "type parameter `{}` is unused", param.name)
.span_label(span, "unused type parameter")
.emit();
result = Err(ErrorReported);
}
}
result
}

fn fatally_break_rust(sess: &Session) {
Expand Down
76 changes: 57 additions & 19 deletions src/librustc_typeck/check/wfcheck.rs
Original file line number Diff line number Diff line change
Expand Up @@ -118,11 +118,64 @@ pub fn check_item_well_formed<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: Def
hir::ItemKind::Fn(..) => {
check_item_fn(tcx, item);
}
hir::ItemKind::Static(..) => {
check_item_type(tcx, item);
}
hir::ItemKind::Static(..) |
hir::ItemKind::Const(..) => {
check_item_type(tcx, item);
for_item(tcx, item).with_fcx(|fcx, _this| {
let ty = fcx.tcx.type_of(fcx.tcx.hir.local_def_id(item.id));
let item_ty = fcx.normalize_associated_types_in(item.span, &ty);

fcx.register_wf_obligation(item_ty, item.span, ObligationCauseCode::MiscObligation);

vec![] // no implied bounds in a static/const
});
}
hir::ItemKind::Ty(..) => {
let def_id = tcx.hir.local_def_id(item.id);
let item_ty = tcx.type_of(def_id);
let generics = tcx.generics_of(def_id);
let used_params = super::check_params_are_used(tcx, &generics, item_ty);
for_item(tcx, item).with_fcx(|fcx, _this| {
// HACK(eddyb) Commented out to not require trait bounds for projections.
// let item_ty = fcx.normalize_associated_types_in(item.span, &item_ty);

// Check the user-declared bounds, assuming the type is WF.
// This ensures that by checking the WF of the aliased type, where
// the alias is used, we don't ignore bounds written on the alias.
// NB: this check only happens if *all* type parameters are used,
// otherwise every unused type parameter can cause errors here.
if let Ok(()) = used_params {
let user_predicates = fcx.param_env.caller_bounds;
let wf_predicates = ty::wf::obligations(
&fcx.infcx,
fcx.param_env,
fcx.body_id,
item_ty,
item.span,
).into_iter().flatten().map(|o| o.predicate).collect();
let wf_predicates = traits::elaborate_predicates(fcx.tcx, wf_predicates);
let wf_param_env = ty::ParamEnv {
caller_bounds: fcx.tcx.mk_predicates(wf_predicates),
reveal: fcx.param_env.reveal,
};
fcx.register_predicates(user_predicates.iter().filter_map(|&predicate| {
// HACK(eddyb) Ignore `Sized` bounds on type parameters.
if let ty::Predicate::Trait(trait_ref) = predicate {
if Some(trait_ref.def_id()) == tcx.lang_items().sized_trait() {
if let ty::Param(_) = trait_ref.skip_binder().self_ty().sty {
return None;
}
}
}

let code = ObligationCauseCode::MiscObligation;
let cause = traits::ObligationCause::new(item.span, fcx.body_id, code);
Some(traits::Obligation::new(cause, wf_param_env, predicate))
}));
}

// HACK(eddyb) Commented out to not require trait bounds for projections.
vec![/*item_ty*/]
});
}
hir::ItemKind::Struct(ref struct_def, ref ast_generics) => {
check_type_defn(tcx, item, false, |fcx| {
Expand Down Expand Up @@ -322,21 +375,6 @@ fn check_item_fn<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, item: &hir::Item) {
})
}

fn check_item_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
item: &hir::Item)
{
debug!("check_item_type: {:?}", item);

for_item(tcx, item).with_fcx(|fcx, _this| {
let ty = fcx.tcx.type_of(fcx.tcx.hir.local_def_id(item.id));
let item_ty = fcx.normalize_associated_types_in(item.span, &ty);

fcx.register_wf_obligation(item_ty, item.span, ObligationCauseCode::MiscObligation);

vec![] // no implied bounds in a const etc
});
}

fn check_impl<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
item: &hir::Item,
ast_self_ty: &hir::Ty,
Expand Down
12 changes: 7 additions & 5 deletions src/test/incremental/hashes/type_defs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -132,12 +132,12 @@ type ChangeNestedTupleField = (i32, (i64, i8));

// Add type param --------------------------------------------------------------
#[cfg(cfail1)]
type AddTypeParam<T1> = (T1, T1);
type AddTypeParam<T1> = (T1, Option<T1>);

#[cfg(not(cfail1))]
#[rustc_clean(cfg="cfail2", except="Hir,HirBody")]
#[rustc_clean(cfg="cfail3")]
type AddTypeParam<T1, T2> = (T1, T2);
type AddTypeParam<T1, T2> = (T1, Option<T2>);



Expand All @@ -148,18 +148,18 @@ type AddTypeParamBound<T1> = (T1, u32);
#[cfg(not(cfail1))]
#[rustc_clean(cfg="cfail2", except="Hir,HirBody")]
#[rustc_clean(cfg="cfail3")]
type AddTypeParamBound<T1: Clone> = (T1, u32);
type AddTypeParamBound<T1: std::any::Any> = (T1, u32);



// Add type param bound in where clause ----------------------------------------
#[cfg(cfail1)]
type AddTypeParamBoundWhereClause<T1> where T1: Clone = (T1, u32);
type AddTypeParamBoundWhereClause<T1> where T1: Sized = (T1, u32);

#[cfg(not(cfail1))]
#[rustc_clean(cfg="cfail2", except="Hir,HirBody")]
#[rustc_clean(cfg="cfail3")]
type AddTypeParamBoundWhereClause<T1> where T1: Clone+Copy = (T1, u32);
type AddTypeParamBoundWhereClause<T1> where T1: Sized+std::any::Any = (T1, u32);



Expand Down Expand Up @@ -203,7 +203,9 @@ where 'b: 'a,

// Change Trait Bound Indirectly -----------------------------------------------
trait ReferencedTrait1 {}
impl<T> ReferencedTrait1 for T {}
trait ReferencedTrait2 {}
impl<T> ReferencedTrait2 for T {}

mod change_trait_bound_indirectly {
#[cfg(cfail1)]
Expand Down
2 changes: 1 addition & 1 deletion src/test/run-pass/attr-on-generic-formals.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ trait TrLt<#[rustc_lt_trait] 'c> { fn foo(&self, _: &'c [u32]) -> &'c u32; }
trait TrTy<#[rustc_ty_trait] K> { fn foo(&self, _: K); }

type TyLt<#[rustc_lt_type] 'd> = &'d u32;
type TyTy<#[rustc_ty_type] L> = (L, );
type TyTy<#[rustc_ty_type] L> = Option<L>;

impl<#[rustc_lt_inherent] 'e> StLt<'e> { }
impl<#[rustc_ty_inherent] M> StTy<M> { }
Expand Down
2 changes: 1 addition & 1 deletion src/test/run-pass/type-param.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,6 @@

// pretty-expanded FIXME #23616

type lteq<T> = extern fn(T) -> bool;
type lteq<T: ?Sized> = extern fn(T) -> bool;

pub fn main() { }
2 changes: 1 addition & 1 deletion src/test/ui/dst/dst-bad-assign-3.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@

#![feature(unsized_tuple_coercion)]

type Fat<T> = (isize, &'static str, T);
type Fat<T: ?Sized> = (isize, &'static str, T);

#[derive(PartialEq,Eq)]
struct Bar;
Expand Down
2 changes: 1 addition & 1 deletion src/test/ui/feature-gates/feature-gate-trivial_bounds.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ trait T where i32: Foo {} //~ ERROR

union U where i32: Foo { f: i32 } //~ ERROR

type Y where i32: Foo = (); // OK - bound is ignored
type Y where i32: Foo = (); //~ ERROR

impl Foo for () where i32: Foo { //~ ERROR
fn test(&self) {
Expand Down
11 changes: 10 additions & 1 deletion src/test/ui/feature-gates/feature-gate-trivial_bounds.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,15 @@ LL | union U where i32: Foo { f: i32 } //~ ERROR
= help: see issue #48214
= help: add #![feature(trivial_bounds)] to the crate attributes to enable

error[E0277]: the trait bound `i32: Foo` is not satisfied
--> $DIR/feature-gate-trivial_bounds.rs:28:1
|
LL | type Y where i32: Foo = (); //~ ERROR
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Foo` is not implemented for `i32`
|
= help: see issue #48214
= help: add #![feature(trivial_bounds)] to the crate attributes to enable

error[E0277]: the trait bound `i32: Foo` is not satisfied
--> $DIR/feature-gate-trivial_bounds.rs:30:1
|
Expand Down Expand Up @@ -125,6 +134,6 @@ LL | | }
= help: see issue #48214
= help: add #![feature(trivial_bounds)] to the crate attributes to enable

error: aborting due to 11 previous errors
error: aborting due to 12 previous errors

For more information about this error, try `rustc --explain E0277`.
2 changes: 1 addition & 1 deletion src/test/ui/generic/generic-param-attrs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ enum EnTy<#[rustc_ty_enum] J> { A(J), B }
trait TrLt<#[rustc_lt_trait] 'c> { fn foo(&self, _: &'c [u32]) -> &'c u32; }
trait TrTy<#[rustc_ty_trait] K> { fn foo(&self, _: K); }
type TyLt<#[rustc_lt_type] 'd> = &'d u32;
type TyTy<#[rustc_ty_type] L> = (L, );
type TyTy<#[rustc_ty_type] L> = Option<L>;

impl<#[rustc_lt_inherent] 'e> StLt<'e> { }
impl<#[rustc_ty_inherent] M> StTy<M> { }
Expand Down
2 changes: 1 addition & 1 deletion src/test/ui/issues/issue-47715.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ union Union<T: Iterable<Item = impl Foo> + Copy> {
x: T,
}

type Type<T: Iterable<Item = impl Foo>> = T;
type Type<T: Iterable<Item = impl Foo>> = Container<T>;
//~^ ERROR `impl Trait` not allowed

fn main() {
Expand Down
2 changes: 1 addition & 1 deletion src/test/ui/issues/issue-47715.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ LL | union Union<T: Iterable<Item = impl Foo> + Copy> {
error[E0562]: `impl Trait` not allowed outside of function and inherent method return types
--> $DIR/issue-47715.rs:34:30
|
LL | type Type<T: Iterable<Item = impl Foo>> = T;
LL | type Type<T: Iterable<Item = impl Foo>> = Container<T>;
| ^^^^^^^^

error: aborting due to 4 previous errors
Expand Down
2 changes: 1 addition & 1 deletion src/test/ui/issues/issue-6936.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ mod t4 {
}

mod t5 {
type Bar<T> = T;
type Bar<T: ?Sized> = T;
mod Bar {} //~ ERROR the name `Bar` is defined multiple times
}

Expand Down
4 changes: 2 additions & 2 deletions src/test/ui/issues/issue-6936.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@ LL | enum Foo {} //~ ERROR the name `Foo` is defined multiple times
error[E0428]: the name `Bar` is defined multiple times
--> $DIR/issue-6936.rs:35:5
|
LL | type Bar<T> = T;
| ---------------- previous definition of the type `Bar` here
LL | type Bar<T: ?Sized> = T;
| ------------------------ previous definition of the type `Bar` here
LL | mod Bar {} //~ ERROR the name `Bar` is defined multiple times
| ^^^^^^^ `Bar` redefined here
|
Expand Down
13 changes: 9 additions & 4 deletions src/test/ui/privacy/private-in-public-warn.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,11 @@ mod traits {
pub struct Pub<T>(T);
pub trait PubTr {}

pub type Alias<T: PrivTr> = T; //~ ERROR private trait `traits::PrivTr` in public interface
//~| WARNING hard error
pub struct Struct<T: PrivTr>(T);
//~^ ERROR private trait `traits::PrivTr` in public interface
pub type Alias<T: PrivTr> = Struct<T>;
//~^ ERROR private trait `traits::PrivTr` in public interface
//~| WARNING hard error
pub trait Tr1: PrivTr {} //~ ERROR private trait `traits::PrivTr` in public interface
//~^ WARNING hard error
pub trait Tr2<T: PrivTr> {} //~ ERROR private trait `traits::PrivTr` in public interface
Expand All @@ -81,7 +84,9 @@ mod traits_where {
pub struct Pub<T>(T);
pub trait PubTr {}

pub type Alias<T> where T: PrivTr = T;
pub struct Struct<T>(T) where T: PrivTr;
//~^ ERROR private trait `traits_where::PrivTr` in public interface
pub type Alias<T> where T: PrivTr = Struct<T>;
//~^ ERROR private trait `traits_where::PrivTr` in public interface
//~| WARNING hard error
pub trait Tr2<T> where T: PrivTr {}
Expand Down Expand Up @@ -273,7 +278,7 @@ mod aliases_priv {

mod aliases_params {
struct Priv;
type PrivAliasGeneric<T = Priv> = T;
type PrivAliasGeneric<T = Priv> = Option<T>;
type Result<T> = ::std::result::Result<T, Priv>;

pub fn f1(arg: PrivAliasGeneric<u8>) {} // OK, not an error
Expand Down
Loading