typeck/type_of: let wfcheck handle duplicate generics in opaque types' substs.

This commit is contained in:
Eduard-Mihai Burtescu 2020-03-22 12:30:24 +02:00
parent 8e9a5d928a
commit 8807b00dd8
10 changed files with 93 additions and 119 deletions

View File

@ -9,7 +9,7 @@ use rustc_hir::def_id::DefId;
use rustc_hir::itemlikevisit::ParItemLikeVisitor;
use rustc_hir::lang_items;
use rustc_hir::ItemKind;
use rustc_middle::ty::subst::{InternalSubsts, Subst};
use rustc_middle::ty::subst::{GenericArgKind, InternalSubsts, Subst};
use rustc_middle::ty::trait_def::TraitSpecializationKind;
use rustc_middle::ty::{
self, AdtKind, GenericParamDefKind, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness,
@ -870,38 +870,17 @@ fn check_opaque_types<'fcx, 'tcx>(
let opaque_hir_id = tcx.hir().as_local_hir_id(def_id).unwrap();
if may_define_opaque_type(tcx, fn_def_id, opaque_hir_id) {
trace!("check_opaque_types: may define, generics={:#?}", generics);
let mut seen: FxHashMap<_, Vec<_>> = FxHashMap::default();
let mut seen_params: FxHashMap<_, Vec<_>> = FxHashMap::default();
for (i, &arg) in substs.iter().enumerate() {
match arg.unpack() {
ty::subst::GenericArgKind::Type(ty) => match ty.kind {
ty::Param(..) => {}
// Prevent `fn foo() -> Foo<u32>` from being defining.
_ => {
tcx.sess
.struct_span_err(
span,
"non-defining opaque type use \
in defining scope",
)
.span_note(
tcx.def_span(generics.param_at(i, tcx).def_id),
&format!(
"used non-generic type `{}` for \
generic parameter",
ty,
),
)
.emit();
}
},
let arg_is_param = match arg.unpack() {
GenericArgKind::Type(ty) => matches!(ty.kind, ty::Param(_)),
ty::subst::GenericArgKind::Lifetime(region) => {
GenericArgKind::Lifetime(region) => {
if let ty::ReStatic = region {
tcx.sess
.struct_span_err(
span,
"non-defining opaque type use \
in defining scope",
"non-defining opaque type use in defining scope",
)
.span_label(
tcx.def_span(generics.param_at(i, tcx).def_id),
@ -910,35 +889,42 @@ fn check_opaque_types<'fcx, 'tcx>(
opaque type",
)
.emit();
} else {
seen.entry(region).or_default().push(i);
continue;
}
true
}
ty::subst::GenericArgKind::Const(ct) => match ct.val {
ty::ConstKind::Param(_) => {}
_ => {
tcx.sess
.struct_span_err(
span,
"non-defining opaque type use \
in defining scope",
)
.span_note(
tcx.def_span(generics.param_at(i, tcx).def_id),
&format!(
"used non-generic const `{}` for \
generic parameter",
ct,
),
)
.emit();
}
},
} // match arg
GenericArgKind::Const(ct) => {
matches!(ct.val, ty::ConstKind::Param(_))
}
};
if arg_is_param {
seen_params.entry(arg).or_default().push(i);
} else {
// Prevent `fn foo() -> Foo<u32>` from being defining.
let opaque_param = generics.param_at(i, tcx);
tcx.sess
.struct_span_err(
span,
"non-defining opaque type use in defining scope",
)
.span_note(
tcx.def_span(opaque_param.def_id),
&format!(
"used non-generic {} `{}` for generic parameter",
opaque_param.kind.descr(),
arg,
),
)
.emit();
}
} // for (arg, param)
for (_, indices) in seen {
for (_, indices) in seen_params {
if indices.len() > 1 {
let descr = generics.param_at(indices[0], tcx).kind.descr();
let spans: Vec<_> = indices
.into_iter()
.map(|i| tcx.def_span(generics.param_at(i, tcx).def_id))
@ -946,10 +932,9 @@ fn check_opaque_types<'fcx, 'tcx>(
tcx.sess
.struct_span_err(
span,
"non-defining opaque type use \
in defining scope",
"non-defining opaque type use in defining scope",
)
.span_note(spans, "lifetime used multiple times")
.span_note(spans, &format!("{} used multiple times", descr))
.emit();
}
}

View File

@ -403,38 +403,43 @@ fn find_opaque_ty_constraints(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> {
// FIXME(oli-obk): trace the actual span from inference to improve errors.
let span = self.tcx.def_span(def_id);
// HACK(eddyb) this check shouldn't be needed, as `wfcheck`
// performs the same checks, in theory, but I've kept it here
// using `delay_span_bug`, just in case `wfcheck` slips up.
let opaque_generics = self.tcx.generics_of(self.def_id);
let mut used_params: FxHashSet<ty::ParamTy> = FxHashSet::default();
let mut duplicate_params: FxHashSet<ty::ParamTy> = FxHashSet::default();
let mut used_params: FxHashSet<_> = FxHashSet::default();
for (i, arg) in substs.iter().enumerate() {
// FIXME(eddyb) enforce lifetime and const param 1:1 mapping.
if let GenericArgKind::Type(ty) = arg.unpack() {
if let ty::Param(p) = ty.kind {
if !used_params.insert(p) && duplicate_params.insert(p) {
// There was already an entry for `p`, meaning a generic parameter
// was used twice.
self.tcx.sess.span_err(
span,
&format!(
"defining opaque type use restricts opaque \
type by using the generic parameter `{}` twice",
p,
),
);
}
} else {
let param = opaque_generics.param_at(i, self.tcx);
let arg_is_param = match arg.unpack() {
GenericArgKind::Type(ty) => matches!(ty.kind, ty::Param(_)),
GenericArgKind::Lifetime(lt) => !matches!(lt, ty::ReStatic),
GenericArgKind::Const(ct) => matches!(ct.val, ty::ConstKind::Param(_)),
};
if arg_is_param {
if !used_params.insert(arg) {
// There was already an entry for `arg`, meaning a generic parameter
// was used twice.
self.tcx.sess.delay_span_bug(
span,
&format!(
"defining opaque type use does not fully define opaque type: \
generic parameter `{}` is specified as concrete {} `{}`",
param.name,
param.kind.descr(),
"defining opaque type use restricts opaque \
type by using the generic parameter `{}` twice",
arg,
),
);
}
} else {
let param = opaque_generics.param_at(i, self.tcx);
self.tcx.sess.delay_span_bug(
span,
&format!(
"defining opaque type use does not fully define opaque type: \
generic parameter `{}` is specified as concrete {} `{}`",
param.name,
param.kind.descr(),
arg,
),
);
}
}

View File

@ -8,6 +8,6 @@ fn main() {}
type Two<T, U> = impl Debug;
fn one<T: Debug>(t: T) -> Two<T, T> {
//~^ ERROR defining opaque type use restricts opaque type
//~^ ERROR non-defining opaque type use in defining scope
t
}

View File

@ -1,11 +1,14 @@
error: defining opaque type use restricts opaque type by using the generic parameter `T` twice
--> $DIR/generic_duplicate_param_use.rs:10:1
error: non-defining opaque type use in defining scope
--> $DIR/generic_duplicate_param_use.rs:10:27
|
LL | / fn one<T: Debug>(t: T) -> Two<T, T> {
LL | |
LL | | t
LL | | }
| |_^
LL | fn one<T: Debug>(t: T) -> Two<T, T> {
| ^^^^^^^^^
|
note: type used multiple times
--> $DIR/generic_duplicate_param_use.rs:8:10
|
LL | type Two<T, U> = impl Debug;
| ^ ^
error: aborting due to previous error

View File

@ -8,7 +8,6 @@ fn main() {}
type Two<T, U> = impl Debug;
fn one<T: Debug>(t: T) -> Two<T, T> {
//~^ ERROR defining opaque type use restricts opaque type
t
}

View File

@ -1,14 +1,5 @@
error: defining opaque type use restricts opaque type by using the generic parameter `T` twice
--> $DIR/generic_duplicate_param_use2.rs:10:1
|
LL | / fn one<T: Debug>(t: T) -> Two<T, T> {
LL | |
LL | | t
LL | | }
| |_^
error: concrete type differs from previous defining opaque type use
--> $DIR/generic_duplicate_param_use2.rs:15:1
--> $DIR/generic_duplicate_param_use2.rs:14:1
|
LL | / fn two<T: Debug, U>(t: T, _: U) -> Two<T, U> {
LL | |
@ -20,10 +11,9 @@ note: previous use here
--> $DIR/generic_duplicate_param_use2.rs:10:1
|
LL | / fn one<T: Debug>(t: T) -> Two<T, T> {
LL | |
LL | | t
LL | | }
| |_^
error: aborting due to 2 previous errors
error: aborting due to previous error

View File

@ -8,7 +8,6 @@ fn main() {}
type Two<T, U> = impl Debug;
fn one<T: Debug>(t: T) -> Two<T, T> {
//~^ ERROR defining opaque type use restricts opaque type
t
}

View File

@ -1,14 +1,5 @@
error: defining opaque type use restricts opaque type by using the generic parameter `T` twice
--> $DIR/generic_duplicate_param_use3.rs:10:1
|
LL | / fn one<T: Debug>(t: T) -> Two<T, T> {
LL | |
LL | | t
LL | | }
| |_^
error: concrete type differs from previous defining opaque type use
--> $DIR/generic_duplicate_param_use3.rs:15:1
--> $DIR/generic_duplicate_param_use3.rs:14:1
|
LL | / fn two<T: Debug, U>(t: T, _: U) -> Two<T, U> {
LL | |
@ -20,10 +11,9 @@ note: previous use here
--> $DIR/generic_duplicate_param_use3.rs:10:1
|
LL | / fn one<T: Debug>(t: T) -> Two<T, T> {
LL | |
LL | | t
LL | | }
| |_^
error: aborting due to 2 previous errors
error: aborting due to previous error

View File

@ -8,7 +8,7 @@ fn main() {}
type Two<T, U> = impl Debug;
fn one<T: Debug>(t: T) -> Two<T, T> {
//~^ ERROR defining opaque type use restricts opaque type
//~^ ERROR non-defining opaque type use in defining scope
t
}

View File

@ -1,11 +1,14 @@
error: defining opaque type use restricts opaque type by using the generic parameter `T` twice
--> $DIR/generic_duplicate_param_use4.rs:10:1
error: non-defining opaque type use in defining scope
--> $DIR/generic_duplicate_param_use4.rs:10:27
|
LL | / fn one<T: Debug>(t: T) -> Two<T, T> {
LL | |
LL | | t
LL | | }
| |_^
LL | fn one<T: Debug>(t: T) -> Two<T, T> {
| ^^^^^^^^^
|
note: type used multiple times
--> $DIR/generic_duplicate_param_use4.rs:8:10
|
LL | type Two<T, U> = impl Debug;
| ^ ^
error: aborting due to previous error