From f1f45f9191d60c52dbedec717aee0de4a0580bcc Mon Sep 17 00:00:00 2001 From: Florian Diebold Date: Fri, 21 Feb 2020 16:56:34 +0100 Subject: Fix handling of const patterns E.g. in `match x { None => ... }`, `None` is a path pattern (resolving to the option variant), not a binding. To determine this, we need to try to resolve the name during lowering. This isn't too hard since we already need to resolve names for macro expansion anyway (though maybe a bit hacky). Fixes #1618. --- crates/ra_hir_def/src/body/lower.rs | 38 ++++++++++++++++++++++++++++++++++--- 1 file changed, 35 insertions(+), 3 deletions(-) (limited to 'crates/ra_hir_def/src/body/lower.rs') diff --git a/crates/ra_hir_def/src/body/lower.rs b/crates/ra_hir_def/src/body/lower.rs index b1626fa11..b3fb6d452 100644 --- a/crates/ra_hir_def/src/body/lower.rs +++ b/crates/ra_hir_def/src/body/lower.rs @@ -15,6 +15,7 @@ use ra_syntax::{ use test_utils::tested_by; use crate::{ + adt::StructKind, body::{Body, BodySourceMap, Expander, PatPtr}, builtin_type::{BuiltinFloat, BuiltinInt}, db::DefDatabase, @@ -22,11 +23,12 @@ use crate::{ ArithOp, Array, BinaryOp, BindingAnnotation, CmpOp, Expr, ExprId, Literal, LogicOp, MatchArm, Ordering, Pat, PatId, RecordFieldPat, RecordLitField, Statement, }, + item_scope::BuiltinShadowMode, path::GenericArgs, path::Path, type_ref::{Mutability, TypeRef}, - ConstLoc, ContainerId, DefWithBodyId, EnumLoc, FunctionLoc, Intern, ModuleDefId, StaticLoc, - StructLoc, TraitLoc, TypeAliasLoc, UnionLoc, + AdtId, ConstLoc, ContainerId, DefWithBodyId, EnumLoc, FunctionLoc, Intern, ModuleDefId, + StaticLoc, StructLoc, TraitLoc, TypeAliasLoc, UnionLoc, }; pub(super) fn lower( @@ -571,7 +573,37 @@ where let name = bp.name().map(|nr| nr.as_name()).unwrap_or_else(Name::missing); let annotation = BindingAnnotation::new(bp.is_mutable(), bp.is_ref()); let subpat = bp.pat().map(|subpat| self.collect_pat(subpat)); - Pat::Bind { name, mode: annotation, subpat } + if annotation == BindingAnnotation::Unannotated && subpat.is_none() { + // This could also be a single-segment path pattern. To + // decide that, we need to try resolving the name. + let (resolved, _) = self.expander.crate_def_map.resolve_path( + self.db, + self.expander.module.local_id, + &name.clone().into(), + BuiltinShadowMode::Other, + ); + match resolved.take_values() { + Some(ModuleDefId::ConstId(_)) => Pat::Path(name.into()), + Some(ModuleDefId::EnumVariantId(_)) => { + // this is only really valid for unit variants, but + // shadowing other enum variants with a pattern is + // an error anyway + Pat::Path(name.into()) + } + Some(ModuleDefId::AdtId(AdtId::StructId(s))) + if self.db.struct_data(s).variant_data.kind() != StructKind::Record => + { + // Funnily enough, record structs *can* be shadowed + // by pattern bindings (but unit or tuple structs + // can't). + Pat::Path(name.into()) + } + // shadowing statics is an error as well, so we just ignore that case here + _ => Pat::Bind { name, mode: annotation, subpat }, + } + } else { + Pat::Bind { name, mode: annotation, subpat } + } } ast::Pat::TupleStructPat(p) => { let path = p.path().and_then(|path| self.expander.parse_path(path)); -- cgit v1.2.3