about summary refs log tree commit diff
diff options
context:
space:
mode:
authorGabriel Smith <gsmith@d3engineering.com>2019-11-18 14:24:13 -0500
committerGabriel Smith <gsmith@d3engineering.com>2019-11-18 17:01:48 -0500
commit7b4642f44178403770cc35166fb676b7fa051bec (patch)
tree416b2f5c0681faeaec854b99da49f3fd1eb88ea7
parent128ca7415f970b13150e90b4705188d7f076d389 (diff)
downloadrust-7b4642f44178403770cc35166fb676b7fa051bec.tar.gz
rust-7b4642f44178403770cc35166fb676b7fa051bec.zip
resolve: late: Check if type arg is really a const arg
A path type argument could be a generic const argument due to
limitations as to what we can determine at parsing. We double check just
to be sure by trying to resolve in the type namespace first, and if that
fails we try again in the value namespace. If resolution in the value
namespace succeeds, we have a generic const argument on our hands.
-rw-r--r--src/librustc_resolve/late.rs46
1 files changed, 46 insertions, 0 deletions
diff --git a/src/librustc_resolve/late.rs b/src/librustc_resolve/late.rs
index 8d11c7224c7..f48df7faea2 100644
--- a/src/librustc_resolve/late.rs
+++ b/src/librustc_resolve/late.rs
@@ -546,6 +546,52 @@ impl<'a, 'tcx> Visitor<'tcx> for LateResolutionVisitor<'a, '_> {
             self.visit_where_predicate(p);
         }
     }
+
+    fn visit_generic_arg(&mut self, arg: &'tcx GenericArg) {
+        debug!("visit_generic_arg({:?})", arg);
+        match arg {
+            GenericArg::Type(ref ty) => {
+                // We parse const arguments as path types as we cannot distiguish them durring
+                // parsing. We try to resolve that ambiguity by attempting resolution the type
+                // namespace first, and if that fails we try again in the value namespace. If
+                // resolution in the value namespace succeeds, we have an generic const argument on
+                // our hands.
+                if let TyKind::Path(ref qself, ref path) = ty.kind {
+                    // We cannot disambiguate multi-segment paths right now as that requires type
+                    // checking.
+                    if path.segments.len() == 1 && path.segments[0].args.is_none() {
+                        let mut check_ns = |ns| self.resolve_ident_in_lexical_scope(
+                            path.segments[0].ident, ns, None, path.span
+                        ).is_some();
+
+                        if !check_ns(TypeNS) && check_ns(ValueNS) {
+                            // This must be equivalent to `visit_anon_const`, but we cannot call it
+                            // directly due to visitor lifetimes so we have to copy-paste some code.
+                            self.with_constant_rib(|this| {
+                                this.smart_resolve_path(
+                                    ty.id,
+                                    qself.as_ref(),
+                                    path,
+                                    PathSource::Expr(None)
+                                );
+
+                                if let Some(ref qself) = *qself {
+                                    this.visit_ty(&qself.ty);
+                                }
+                                this.visit_path(path, ty.id);
+                            });
+
+                            return;
+                        }
+                    }
+                }
+
+                self.visit_ty(ty);
+            }
+            GenericArg::Lifetime(lt) => self.visit_lifetime(lt),
+            GenericArg::Const(ct) => self.visit_anon_const(ct),
+        }
+    }
 }
 
 impl<'a, 'b> LateResolutionVisitor<'a, '_> {