Skip to content

Commit 6465113

Browse files
committed
typeck/type_of: simplify checking of opaque types with multipler defining uses.
1 parent f6fe99c commit 6465113

File tree

4 files changed

+53
-122
lines changed

4 files changed

+53
-122
lines changed

src/librustc_middle/ty/mod.rs

Lines changed: 21 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1077,48 +1077,42 @@ impl<'tcx> Generics {
10771077
false
10781078
}
10791079

1080+
pub fn param_at(&'tcx self, param_index: usize, tcx: TyCtxt<'tcx>) -> &'tcx GenericParamDef {
1081+
if let Some(index) = param_index.checked_sub(self.parent_count) {
1082+
&self.params[index]
1083+
} else {
1084+
tcx.generics_of(self.parent.expect("parent_count > 0 but no parent?"))
1085+
.param_at(param_index, tcx)
1086+
}
1087+
}
1088+
10801089
pub fn region_param(
10811090
&'tcx self,
10821091
param: &EarlyBoundRegion,
10831092
tcx: TyCtxt<'tcx>,
10841093
) -> &'tcx GenericParamDef {
1085-
if let Some(index) = param.index.checked_sub(self.parent_count as u32) {
1086-
let param = &self.params[index as usize];
1087-
match param.kind {
1088-
GenericParamDefKind::Lifetime => param,
1089-
_ => bug!("expected lifetime parameter, but found another generic parameter"),
1090-
}
1091-
} else {
1092-
tcx.generics_of(self.parent.expect("parent_count > 0 but no parent?"))
1093-
.region_param(param, tcx)
1094+
let param = self.param_at(param.index as usize, tcx);
1095+
match param.kind {
1096+
GenericParamDefKind::Lifetime => param,
1097+
_ => bug!("expected lifetime parameter, but found another generic parameter"),
10941098
}
10951099
}
10961100

10971101
/// Returns the `GenericParamDef` associated with this `ParamTy`.
10981102
pub fn type_param(&'tcx self, param: &ParamTy, tcx: TyCtxt<'tcx>) -> &'tcx GenericParamDef {
1099-
if let Some(index) = param.index.checked_sub(self.parent_count as u32) {
1100-
let param = &self.params[index as usize];
1101-
match param.kind {
1102-
GenericParamDefKind::Type { .. } => param,
1103-
_ => bug!("expected type parameter, but found another generic parameter"),
1104-
}
1105-
} else {
1106-
tcx.generics_of(self.parent.expect("parent_count > 0 but no parent?"))
1107-
.type_param(param, tcx)
1103+
let param = self.param_at(param.index as usize, tcx);
1104+
match param.kind {
1105+
GenericParamDefKind::Type { .. } => param,
1106+
_ => bug!("expected type parameter, but found another generic parameter"),
11081107
}
11091108
}
11101109

11111110
/// Returns the `ConstParameterDef` associated with this `ParamConst`.
11121111
pub fn const_param(&'tcx self, param: &ParamConst, tcx: TyCtxt<'tcx>) -> &GenericParamDef {
1113-
if let Some(index) = param.index.checked_sub(self.parent_count as u32) {
1114-
let param = &self.params[index as usize];
1115-
match param.kind {
1116-
GenericParamDefKind::Const => param,
1117-
_ => bug!("expected const parameter, but found another generic parameter"),
1118-
}
1119-
} else {
1120-
tcx.generics_of(self.parent.expect("parent_count>0 but no parent?"))
1121-
.const_param(param, tcx)
1112+
let param = self.param_at(param.index as usize, tcx);
1113+
match param.kind {
1114+
GenericParamDefKind::Const => param,
1115+
_ => bug!("expected const parameter, but found another generic parameter"),
11221116
}
11231117
}
11241118
}

src/librustc_typeck/collect/type_of.rs

Lines changed: 29 additions & 92 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use rustc_data_structures::fx::FxHashMap;
1+
use rustc_data_structures::fx::FxHashSet;
22
use rustc_errors::{struct_span_err, Applicability, StashKey};
33
use rustc_hir as hir;
44
use rustc_hir::def::{DefKind, Res};
@@ -7,7 +7,7 @@ use rustc_hir::intravisit;
77
use rustc_hir::intravisit::Visitor;
88
use rustc_hir::Node;
99
use rustc_middle::hir::map::Map;
10-
use rustc_middle::ty::subst::{GenericArgKind, InternalSubsts, Subst};
10+
use rustc_middle::ty::subst::{GenericArgKind, InternalSubsts};
1111
use rustc_middle::ty::util::IntTypeExt;
1212
use rustc_middle::ty::{self, DefIdTree, Ty, TyCtxt, TypeFoldable};
1313
use rustc_session::parse::feature_err;
@@ -369,13 +369,8 @@ fn find_opaque_ty_constraints(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> {
369369
struct ConstraintLocator<'tcx> {
370370
tcx: TyCtxt<'tcx>,
371371
def_id: DefId,
372-
// (first found type span, actual type, mapping from the opaque type's generic
373-
// parameters to the concrete type's generic parameters)
374-
//
375-
// The mapping is an index for each use site of a generic parameter in the concrete type
376-
//
377-
// The indices index into the generic parameters on the opaque type.
378-
found: Option<(Span, Ty<'tcx>, Vec<usize>)>,
372+
// (first found type span, actual type)
373+
found: Option<(Span, Ty<'tcx>)>,
379374
}
380375

381376
impl ConstraintLocator<'_> {
@@ -407,14 +402,15 @@ fn find_opaque_ty_constraints(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> {
407402

408403
// FIXME(oli-obk): trace the actual span from inference to improve errors.
409404
let span = self.tcx.def_span(def_id);
410-
// used to quickly look up the position of a generic parameter
411-
let mut index_map: FxHashMap<ty::ParamTy, usize> = FxHashMap::default();
412-
// Skipping binder is ok, since we only use this to find generic parameters and
413-
// their positions.
414-
for (idx, subst) in substs.iter().enumerate() {
415-
if let GenericArgKind::Type(ty) = subst.unpack() {
405+
406+
let opaque_generics = self.tcx.generics_of(self.def_id);
407+
let mut used_params: FxHashSet<ty::ParamTy> = FxHashSet::default();
408+
let mut has_errors = false;
409+
for (i, arg) in substs.iter().enumerate() {
410+
// FIXME(eddyb) enforce lifetime and const param 1:1 mapping.
411+
if let GenericArgKind::Type(ty) = arg.unpack() {
416412
if let ty::Param(p) = ty.kind {
417-
if index_map.insert(p, idx).is_some() {
413+
if !used_params.insert(p) {
418414
// There was already an entry for `p`, meaning a generic parameter
419415
// was used twice.
420416
self.tcx.sess.span_err(
@@ -428,62 +424,28 @@ fn find_opaque_ty_constraints(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> {
428424
return;
429425
}
430426
} else {
431-
self.tcx.sess.delay_span_bug(
427+
let param = opaque_generics.param_at(i, self.tcx);
428+
self.tcx.sess.span_err(
432429
span,
433430
&format!(
434-
"non-defining opaque ty use in defining scope: {:?}, {:?}",
435-
concrete_type, substs,
431+
"defining opaque type use does not fully define opaque type: \
432+
generic parameter `{}` is specified as concrete {} `{}`",
433+
param.name,
434+
param.kind.descr(),
435+
arg,
436436
),
437437
);
438+
has_errors = true;
438439
}
439440
}
440441
}
441-
// Compute the index within the opaque type for each generic parameter used in
442-
// the concrete type.
443-
let indices = concrete_type
444-
.subst(self.tcx, substs)
445-
.walk()
446-
.filter_map(|t| match &t.kind {
447-
ty::Param(p) => Some(*index_map.get(p).unwrap()),
448-
_ => None,
449-
})
450-
.collect();
451-
let is_param = |ty: Ty<'_>| match ty.kind {
452-
ty::Param(_) => true,
453-
_ => false,
454-
};
455-
let bad_substs: Vec<_> = substs
456-
.iter()
457-
.enumerate()
458-
.filter_map(|(i, k)| {
459-
if let GenericArgKind::Type(ty) = k.unpack() { Some((i, ty)) } else { None }
460-
})
461-
.filter(|(_, ty)| !is_param(ty))
462-
.collect();
463-
if !bad_substs.is_empty() {
464-
let identity_substs = InternalSubsts::identity_for_item(self.tcx, self.def_id);
465-
for (i, bad_subst) in bad_substs {
466-
self.tcx.sess.span_err(
467-
span,
468-
&format!(
469-
"defining opaque type use does not fully define opaque type: \
470-
generic parameter `{}` is specified as concrete type `{}`",
471-
identity_substs.type_at(i),
472-
bad_subst
473-
),
474-
);
475-
}
476-
} else if let Some((prev_span, prev_ty, ref prev_indices)) = self.found {
477-
let mut ty = concrete_type.walk().fuse();
478-
let mut p_ty = prev_ty.walk().fuse();
479-
let iter_eq = (&mut ty).zip(&mut p_ty).all(|(t, p)| match (&t.kind, &p.kind) {
480-
// Type parameters are equal to any other type parameter for the purpose of
481-
// concrete type equality, as it is possible to obtain the same type just
482-
// by passing matching parameters to a function.
483-
(ty::Param(_), ty::Param(_)) => true,
484-
_ => t == p,
485-
});
486-
if !iter_eq || ty.next().is_some() || p_ty.next().is_some() {
442+
443+
if has_errors {
444+
return;
445+
}
446+
447+
if let Some((prev_span, prev_ty)) = self.found {
448+
if *concrete_type != prev_ty {
487449
debug!("find_opaque_ty_constraints: span={:?}", span);
488450
// Found different concrete types for the opaque type.
489451
let mut err = self.tcx.sess.struct_span_err(
@@ -496,34 +458,9 @@ fn find_opaque_ty_constraints(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> {
496458
);
497459
err.span_note(prev_span, "previous use here");
498460
err.emit();
499-
} else if indices != *prev_indices {
500-
// Found "same" concrete types, but the generic parameter order differs.
501-
let mut err = self.tcx.sess.struct_span_err(
502-
span,
503-
"concrete type's generic parameters differ from previous defining use",
504-
);
505-
use std::fmt::Write;
506-
let mut s = String::new();
507-
write!(s, "expected [").unwrap();
508-
let list = |s: &mut String, indices: &Vec<usize>| {
509-
let mut indices = indices.iter().cloned();
510-
if let Some(first) = indices.next() {
511-
write!(s, "`{}`", substs[first]).unwrap();
512-
for i in indices {
513-
write!(s, ", `{}`", substs[i]).unwrap();
514-
}
515-
}
516-
};
517-
list(&mut s, prev_indices);
518-
write!(s, "], got [").unwrap();
519-
list(&mut s, &indices);
520-
write!(s, "]").unwrap();
521-
err.span_label(span, s);
522-
err.span_note(prev_span, "previous use here");
523-
err.emit();
524461
}
525462
} else {
526-
self.found = Some((span, concrete_type, indices));
463+
self.found = Some((span, concrete_type));
527464
}
528465
} else {
529466
debug!(
@@ -606,7 +543,7 @@ fn find_opaque_ty_constraints(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> {
606543
}
607544

608545
match locator.found {
609-
Some((_, ty, _)) => ty,
546+
Some((_, ty)) => ty,
610547
None => {
611548
let span = tcx.def_span(def_id);
612549
tcx.sess.span_err(span, "could not find defining uses");

src/test/ui/type-alias-impl-trait/generic_duplicate_param_use3.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,6 @@ fn two<T: Debug, U>(t: T, _: U) -> Two<T, U> {
1717
}
1818

1919
fn three<T, U: Debug>(_: T, u: U) -> Two<T, U> {
20-
//~^ concrete type's generic parameters differ from previous defining use
20+
//~^ concrete type differs from previous defining opaque type use
2121
u
2222
}

src/test/ui/type-alias-impl-trait/generic_duplicate_param_use3.stderr

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,14 @@ LL | | t
77
LL | | }
88
| |_^
99

10-
error: concrete type's generic parameters differ from previous defining use
10+
error: concrete type differs from previous defining opaque type use
1111
--> $DIR/generic_duplicate_param_use3.rs:19:1
1212
|
1313
LL | / fn three<T, U: Debug>(_: T, u: U) -> Two<T, U> {
1414
LL | |
1515
LL | | u
1616
LL | | }
17-
| |_^ expected [`T`], got [`U`]
17+
| |_^ expected `T`, got `U`
1818
|
1919
note: previous use here
2020
--> $DIR/generic_duplicate_param_use3.rs:15:1

0 commit comments

Comments
 (0)