Skip to content

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

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 3 commits into from
Closed
Changes from 1 commit
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
Next Next commit
rustc_typeck: ensure type alias bounds are implied by the type being …
…well-formed.
  • Loading branch information
eddyb committed Sep 9, 2018
commit 0732b58fb49fdf290cdef6bf68e0ebec24e08481
25 changes: 16 additions & 9 deletions src/librustc_typeck/check/mod.rs
Original file line number Diff line number Diff line change
@@ -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);
@@ -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];
@@ -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) {
65 changes: 46 additions & 19 deletions src/librustc_typeck/check/wfcheck.rs
Original file line number Diff line number Diff line change
@@ -118,11 +118,53 @@ 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| {
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().map(|&predicate| {
let code = ObligationCauseCode::MiscObligation;
let cause = traits::ObligationCause::new(item.span, fcx.body_id, code);
traits::Obligation::new(cause, wf_param_env, predicate)
}));
}

vec![item_ty]
});
}
hir::ItemKind::Struct(ref struct_def, ref ast_generics) => {
check_type_defn(tcx, item, false, |fcx| {
@@ -322,21 +364,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,
12 changes: 7 additions & 5 deletions src/test/incremental/hashes/type_defs.rs
Original file line number Diff line number Diff line change
@@ -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>);



@@ -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);



@@ -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)]
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
@@ -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> { }
2 changes: 1 addition & 1 deletion src/test/run-pass/type-param.rs
Original file line number Diff line number Diff line change
@@ -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() { }
20 changes: 10 additions & 10 deletions src/test/ui/consts/const-eval/pub_const_err.stderr
Original file line number Diff line number Diff line change
@@ -1,22 +1,22 @@
warning: this constant cannot be used
--> $DIR/pub_const_err.rs:16:1
warning: attempt to subtract with overflow
--> $DIR/pub_const_err.rs:19:22
|
LL | pub const Z: u32 = 0 - 1;
| ^^^^^^^^^^^^^^^^^^^-----^
| |
| attempt to subtract with overflow
LL | pub type Foo = [i32; 0 - 1];
| ^^^^^
|
note: lint level defined here
--> $DIR/pub_const_err.rs:12:9
|
LL | #![warn(const_err)]
| ^^^^^^^^^

warning: attempt to subtract with overflow
--> $DIR/pub_const_err.rs:19:22
warning: this constant cannot be used
--> $DIR/pub_const_err.rs:16:1
|
LL | pub type Foo = [i32; 0 - 1];
| ^^^^^
LL | pub const Z: u32 = 0 - 1;
| ^^^^^^^^^^^^^^^^^^^-----^
| |
| attempt to subtract with overflow

warning: this array length cannot be used
--> $DIR/pub_const_err.rs:19:22
20 changes: 10 additions & 10 deletions src/test/ui/consts/const-eval/pub_const_err_bin.stderr
Original file line number Diff line number Diff line change
@@ -1,22 +1,22 @@
warning: this constant cannot be used
--> $DIR/pub_const_err_bin.rs:14:1
warning: attempt to subtract with overflow
--> $DIR/pub_const_err_bin.rs:17:22
|
LL | pub const Z: u32 = 0 - 1;
| ^^^^^^^^^^^^^^^^^^^-----^
| |
| attempt to subtract with overflow
LL | pub type Foo = [i32; 0 - 1];
| ^^^^^
|
note: lint level defined here
--> $DIR/pub_const_err_bin.rs:12:9
|
LL | #![warn(const_err)]
| ^^^^^^^^^

warning: attempt to subtract with overflow
--> $DIR/pub_const_err_bin.rs:17:22
warning: this constant cannot be used
--> $DIR/pub_const_err_bin.rs:14:1
|
LL | pub type Foo = [i32; 0 - 1];
| ^^^^^
LL | pub const Z: u32 = 0 - 1;
| ^^^^^^^^^^^^^^^^^^^-----^
| |
| attempt to subtract with overflow

warning: this array length cannot be used
--> $DIR/pub_const_err_bin.rs:17:22
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
@@ -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;
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
@@ -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) {
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
@@ -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
|
@@ -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
@@ -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> { }
2 changes: 1 addition & 1 deletion src/test/ui/issues/issue-47715.rs
Original file line number Diff line number Diff line change
@@ -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() {
2 changes: 1 addition & 1 deletion src/test/ui/issues/issue-47715.stderr
Original file line number Diff line number Diff line change
@@ -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
2 changes: 1 addition & 1 deletion src/test/ui/issues/issue-6936.rs
Original file line number Diff line number Diff line change
@@ -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
}

4 changes: 2 additions & 2 deletions src/test/ui/issues/issue-6936.stderr
Original file line number Diff line number Diff line change
@@ -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
|
Loading