about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorEduard-Mihai Burtescu <edy.burt@gmail.com>2020-03-22 11:01:46 +0200
committerEduard-Mihai Burtescu <edy.burt@gmail.com>2020-04-04 06:49:20 +0300
commit64651138524b45a7e18bec7dcaf143c7fa4f2794 (patch)
tree0b03690c8acbb82b0641acc66097fa19da754a5d /src
parentf6fe99c798cb65280a9a56f442b371adcb7b8aa2 (diff)
downloadrust-64651138524b45a7e18bec7dcaf143c7fa4f2794.tar.gz
rust-64651138524b45a7e18bec7dcaf143c7fa4f2794.zip
typeck/type_of: simplify checking of opaque types with multipler defining uses.
Diffstat (limited to 'src')
-rw-r--r--src/librustc_middle/ty/mod.rs48
-rw-r--r--src/librustc_typeck/collect/type_of.rs121
-rw-r--r--src/test/ui/type-alias-impl-trait/generic_duplicate_param_use3.rs2
-rw-r--r--src/test/ui/type-alias-impl-trait/generic_duplicate_param_use3.stderr4
4 files changed, 53 insertions, 122 deletions
diff --git a/src/librustc_middle/ty/mod.rs b/src/librustc_middle/ty/mod.rs
index 901365ef691..9b182333907 100644
--- a/src/librustc_middle/ty/mod.rs
+++ b/src/librustc_middle/ty/mod.rs
@@ -1077,48 +1077,42 @@ impl<'tcx> Generics {
         false
     }
 
+    pub fn param_at(&'tcx self, param_index: usize, tcx: TyCtxt<'tcx>) -> &'tcx GenericParamDef {
+        if let Some(index) = param_index.checked_sub(self.parent_count) {
+            &self.params[index]
+        } else {
+            tcx.generics_of(self.parent.expect("parent_count > 0 but no parent?"))
+                .param_at(param_index, tcx)
+        }
+    }
+
     pub fn region_param(
         &'tcx self,
         param: &EarlyBoundRegion,
         tcx: TyCtxt<'tcx>,
     ) -> &'tcx GenericParamDef {
-        if let Some(index) = param.index.checked_sub(self.parent_count as u32) {
-            let param = &self.params[index as usize];
-            match param.kind {
-                GenericParamDefKind::Lifetime => param,
-                _ => bug!("expected lifetime parameter, but found another generic parameter"),
-            }
-        } else {
-            tcx.generics_of(self.parent.expect("parent_count > 0 but no parent?"))
-                .region_param(param, tcx)
+        let param = self.param_at(param.index as usize, tcx);
+        match param.kind {
+            GenericParamDefKind::Lifetime => param,
+            _ => bug!("expected lifetime parameter, but found another generic parameter"),
         }
     }
 
     /// Returns the `GenericParamDef` associated with this `ParamTy`.
     pub fn type_param(&'tcx self, param: &ParamTy, tcx: TyCtxt<'tcx>) -> &'tcx GenericParamDef {
-        if let Some(index) = param.index.checked_sub(self.parent_count as u32) {
-            let param = &self.params[index as usize];
-            match param.kind {
-                GenericParamDefKind::Type { .. } => param,
-                _ => bug!("expected type parameter, but found another generic parameter"),
-            }
-        } else {
-            tcx.generics_of(self.parent.expect("parent_count > 0 but no parent?"))
-                .type_param(param, tcx)
+        let param = self.param_at(param.index as usize, tcx);
+        match param.kind {
+            GenericParamDefKind::Type { .. } => param,
+            _ => bug!("expected type parameter, but found another generic parameter"),
         }
     }
 
     /// Returns the `ConstParameterDef` associated with this `ParamConst`.
     pub fn const_param(&'tcx self, param: &ParamConst, tcx: TyCtxt<'tcx>) -> &GenericParamDef {
-        if let Some(index) = param.index.checked_sub(self.parent_count as u32) {
-            let param = &self.params[index as usize];
-            match param.kind {
-                GenericParamDefKind::Const => param,
-                _ => bug!("expected const parameter, but found another generic parameter"),
-            }
-        } else {
-            tcx.generics_of(self.parent.expect("parent_count>0 but no parent?"))
-                .const_param(param, tcx)
+        let param = self.param_at(param.index as usize, tcx);
+        match param.kind {
+            GenericParamDefKind::Const => param,
+            _ => bug!("expected const parameter, but found another generic parameter"),
         }
     }
 }
diff --git a/src/librustc_typeck/collect/type_of.rs b/src/librustc_typeck/collect/type_of.rs
index e6099b98dc8..acf593c2912 100644
--- a/src/librustc_typeck/collect/type_of.rs
+++ b/src/librustc_typeck/collect/type_of.rs
@@ -1,4 +1,4 @@
-use rustc_data_structures::fx::FxHashMap;
+use rustc_data_structures::fx::FxHashSet;
 use rustc_errors::{struct_span_err, Applicability, StashKey};
 use rustc_hir as hir;
 use rustc_hir::def::{DefKind, Res};
@@ -7,7 +7,7 @@ use rustc_hir::intravisit;
 use rustc_hir::intravisit::Visitor;
 use rustc_hir::Node;
 use rustc_middle::hir::map::Map;
-use rustc_middle::ty::subst::{GenericArgKind, InternalSubsts, Subst};
+use rustc_middle::ty::subst::{GenericArgKind, InternalSubsts};
 use rustc_middle::ty::util::IntTypeExt;
 use rustc_middle::ty::{self, DefIdTree, Ty, TyCtxt, TypeFoldable};
 use rustc_session::parse::feature_err;
@@ -369,13 +369,8 @@ fn find_opaque_ty_constraints(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> {
     struct ConstraintLocator<'tcx> {
         tcx: TyCtxt<'tcx>,
         def_id: DefId,
-        // (first found type span, actual type, mapping from the opaque type's generic
-        // parameters to the concrete type's generic parameters)
-        //
-        // The mapping is an index for each use site of a generic parameter in the concrete type
-        //
-        // The indices index into the generic parameters on the opaque type.
-        found: Option<(Span, Ty<'tcx>, Vec<usize>)>,
+        // (first found type span, actual type)
+        found: Option<(Span, Ty<'tcx>)>,
     }
 
     impl ConstraintLocator<'_> {
@@ -407,14 +402,15 @@ 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);
-                // used to quickly look up the position of a generic parameter
-                let mut index_map: FxHashMap<ty::ParamTy, usize> = FxHashMap::default();
-                // Skipping binder is ok, since we only use this to find generic parameters and
-                // their positions.
-                for (idx, subst) in substs.iter().enumerate() {
-                    if let GenericArgKind::Type(ty) = subst.unpack() {
+
+                let opaque_generics = self.tcx.generics_of(self.def_id);
+                let mut used_params: FxHashSet<ty::ParamTy> = FxHashSet::default();
+                let mut has_errors = false;
+                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 index_map.insert(p, idx).is_some() {
+                            if !used_params.insert(p) {
                                 // There was already an entry for `p`, meaning a generic parameter
                                 // was used twice.
                                 self.tcx.sess.span_err(
@@ -428,62 +424,28 @@ fn find_opaque_ty_constraints(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> {
                                 return;
                             }
                         } else {
-                            self.tcx.sess.delay_span_bug(
+                            let param = opaque_generics.param_at(i, self.tcx);
+                            self.tcx.sess.span_err(
                                 span,
                                 &format!(
-                                    "non-defining opaque ty use in defining scope: {:?}, {:?}",
-                                    concrete_type, substs,
+                                    "defining opaque type use does not fully define opaque type: \
+                                     generic parameter `{}` is specified as concrete {} `{}`",
+                                    param.name,
+                                    param.kind.descr(),
+                                    arg,
                                 ),
                             );
+                            has_errors = true;
                         }
                     }
                 }
-                // Compute the index within the opaque type for each generic parameter used in
-                // the concrete type.
-                let indices = concrete_type
-                    .subst(self.tcx, substs)
-                    .walk()
-                    .filter_map(|t| match &t.kind {
-                        ty::Param(p) => Some(*index_map.get(p).unwrap()),
-                        _ => None,
-                    })
-                    .collect();
-                let is_param = |ty: Ty<'_>| match ty.kind {
-                    ty::Param(_) => true,
-                    _ => false,
-                };
-                let bad_substs: Vec<_> = substs
-                    .iter()
-                    .enumerate()
-                    .filter_map(|(i, k)| {
-                        if let GenericArgKind::Type(ty) = k.unpack() { Some((i, ty)) } else { None }
-                    })
-                    .filter(|(_, ty)| !is_param(ty))
-                    .collect();
-                if !bad_substs.is_empty() {
-                    let identity_substs = InternalSubsts::identity_for_item(self.tcx, self.def_id);
-                    for (i, bad_subst) in bad_substs {
-                        self.tcx.sess.span_err(
-                            span,
-                            &format!(
-                                "defining opaque type use does not fully define opaque type: \
-                            generic parameter `{}` is specified as concrete type `{}`",
-                                identity_substs.type_at(i),
-                                bad_subst
-                            ),
-                        );
-                    }
-                } else if let Some((prev_span, prev_ty, ref prev_indices)) = self.found {
-                    let mut ty = concrete_type.walk().fuse();
-                    let mut p_ty = prev_ty.walk().fuse();
-                    let iter_eq = (&mut ty).zip(&mut p_ty).all(|(t, p)| match (&t.kind, &p.kind) {
-                        // Type parameters are equal to any other type parameter for the purpose of
-                        // concrete type equality, as it is possible to obtain the same type just
-                        // by passing matching parameters to a function.
-                        (ty::Param(_), ty::Param(_)) => true,
-                        _ => t == p,
-                    });
-                    if !iter_eq || ty.next().is_some() || p_ty.next().is_some() {
+
+                if has_errors {
+                    return;
+                }
+
+                if let Some((prev_span, prev_ty)) = self.found {
+                    if *concrete_type != prev_ty {
                         debug!("find_opaque_ty_constraints: span={:?}", span);
                         // Found different concrete types for the opaque type.
                         let mut err = self.tcx.sess.struct_span_err(
@@ -496,34 +458,9 @@ fn find_opaque_ty_constraints(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> {
                         );
                         err.span_note(prev_span, "previous use here");
                         err.emit();
-                    } else if indices != *prev_indices {
-                        // Found "same" concrete types, but the generic parameter order differs.
-                        let mut err = self.tcx.sess.struct_span_err(
-                            span,
-                            "concrete type's generic parameters differ from previous defining use",
-                        );
-                        use std::fmt::Write;
-                        let mut s = String::new();
-                        write!(s, "expected [").unwrap();
-                        let list = |s: &mut String, indices: &Vec<usize>| {
-                            let mut indices = indices.iter().cloned();
-                            if let Some(first) = indices.next() {
-                                write!(s, "`{}`", substs[first]).unwrap();
-                                for i in indices {
-                                    write!(s, ", `{}`", substs[i]).unwrap();
-                                }
-                            }
-                        };
-                        list(&mut s, prev_indices);
-                        write!(s, "], got [").unwrap();
-                        list(&mut s, &indices);
-                        write!(s, "]").unwrap();
-                        err.span_label(span, s);
-                        err.span_note(prev_span, "previous use here");
-                        err.emit();
                     }
                 } else {
-                    self.found = Some((span, concrete_type, indices));
+                    self.found = Some((span, concrete_type));
                 }
             } else {
                 debug!(
@@ -606,7 +543,7 @@ fn find_opaque_ty_constraints(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> {
     }
 
     match locator.found {
-        Some((_, ty, _)) => ty,
+        Some((_, ty)) => ty,
         None => {
             let span = tcx.def_span(def_id);
             tcx.sess.span_err(span, "could not find defining uses");
diff --git a/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use3.rs b/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use3.rs
index 8d3e7f9f424..ec9f40851c5 100644
--- a/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use3.rs
+++ b/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use3.rs
@@ -17,6 +17,6 @@ fn two<T: Debug, U>(t: T, _: U) -> Two<T, U> {
 }
 
 fn three<T, U: Debug>(_: T, u: U) -> Two<T, U> {
-//~^ concrete type's generic parameters differ from previous defining use
+//~^ concrete type differs from previous defining opaque type use
     u
 }
diff --git a/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use3.stderr b/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use3.stderr
index 04dcdc295f9..51bee41aba3 100644
--- a/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use3.stderr
+++ b/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use3.stderr
@@ -7,14 +7,14 @@ LL | |     t
 LL | | }
    | |_^
 
-error: concrete type's generic parameters differ from previous defining use
+error: concrete type differs from previous defining opaque type use
   --> $DIR/generic_duplicate_param_use3.rs:19:1
    |
 LL | / fn three<T, U: Debug>(_: T, u: U) -> Two<T, U> {
 LL | |
 LL | |     u
 LL | | }
-   | |_^ expected [`T`], got [`U`]
+   | |_^ expected `T`, got `U`
    |
 note: previous use here
   --> $DIR/generic_duplicate_param_use3.rs:15:1