aboutsummaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
authorFlorian Diebold <[email protected]>2020-02-21 15:56:34 +0000
committerFlorian Diebold <[email protected]>2020-02-21 16:01:19 +0000
commitf1f45f9191d60c52dbedec717aee0de4a0580bcc (patch)
treebaebf708dcdc154fbe4fe903906e11e344a09802 /crates
parente3037c2631ecb55996b676ce2c18b9df1858abaa (diff)
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.
Diffstat (limited to 'crates')
-rw-r--r--crates/ra_hir_def/src/adt.rs1
-rw-r--r--crates/ra_hir_def/src/body/lower.rs38
-rw-r--r--crates/ra_hir_def/src/expr.rs2
-rw-r--r--crates/ra_hir_ty/src/infer/pat.rs4
-rw-r--r--crates/ra_hir_ty/src/tests/patterns.rs46
5 files changed, 85 insertions, 6 deletions
diff --git a/crates/ra_hir_def/src/adt.rs b/crates/ra_hir_def/src/adt.rs
index 985f409e8..2bdfc2b8d 100644
--- a/crates/ra_hir_def/src/adt.rs
+++ b/crates/ra_hir_def/src/adt.rs
@@ -174,6 +174,7 @@ impl HasChildSource for VariantId {
174 } 174 }
175} 175}
176 176
177#[derive(Debug, Copy, Clone, PartialEq, Eq)]
177pub enum StructKind { 178pub enum StructKind {
178 Tuple, 179 Tuple,
179 Record, 180 Record,
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::{
15use test_utils::tested_by; 15use test_utils::tested_by;
16 16
17use crate::{ 17use crate::{
18 adt::StructKind,
18 body::{Body, BodySourceMap, Expander, PatPtr}, 19 body::{Body, BodySourceMap, Expander, PatPtr},
19 builtin_type::{BuiltinFloat, BuiltinInt}, 20 builtin_type::{BuiltinFloat, BuiltinInt},
20 db::DefDatabase, 21 db::DefDatabase,
@@ -22,11 +23,12 @@ use crate::{
22 ArithOp, Array, BinaryOp, BindingAnnotation, CmpOp, Expr, ExprId, Literal, LogicOp, 23 ArithOp, Array, BinaryOp, BindingAnnotation, CmpOp, Expr, ExprId, Literal, LogicOp,
23 MatchArm, Ordering, Pat, PatId, RecordFieldPat, RecordLitField, Statement, 24 MatchArm, Ordering, Pat, PatId, RecordFieldPat, RecordLitField, Statement,
24 }, 25 },
26 item_scope::BuiltinShadowMode,
25 path::GenericArgs, 27 path::GenericArgs,
26 path::Path, 28 path::Path,
27 type_ref::{Mutability, TypeRef}, 29 type_ref::{Mutability, TypeRef},
28 ConstLoc, ContainerId, DefWithBodyId, EnumLoc, FunctionLoc, Intern, ModuleDefId, StaticLoc, 30 AdtId, ConstLoc, ContainerId, DefWithBodyId, EnumLoc, FunctionLoc, Intern, ModuleDefId,
29 StructLoc, TraitLoc, TypeAliasLoc, UnionLoc, 31 StaticLoc, StructLoc, TraitLoc, TypeAliasLoc, UnionLoc,
30}; 32};
31 33
32pub(super) fn lower( 34pub(super) fn lower(
@@ -571,7 +573,37 @@ where
571 let name = bp.name().map(|nr| nr.as_name()).unwrap_or_else(Name::missing); 573 let name = bp.name().map(|nr| nr.as_name()).unwrap_or_else(Name::missing);
572 let annotation = BindingAnnotation::new(bp.is_mutable(), bp.is_ref()); 574 let annotation = BindingAnnotation::new(bp.is_mutable(), bp.is_ref());
573 let subpat = bp.pat().map(|subpat| self.collect_pat(subpat)); 575 let subpat = bp.pat().map(|subpat| self.collect_pat(subpat));
574 Pat::Bind { name, mode: annotation, subpat } 576 if annotation == BindingAnnotation::Unannotated && subpat.is_none() {
577 // This could also be a single-segment path pattern. To
578 // decide that, we need to try resolving the name.
579 let (resolved, _) = self.expander.crate_def_map.resolve_path(
580 self.db,
581 self.expander.module.local_id,
582 &name.clone().into(),
583 BuiltinShadowMode::Other,
584 );
585 match resolved.take_values() {
586 Some(ModuleDefId::ConstId(_)) => Pat::Path(name.into()),
587 Some(ModuleDefId::EnumVariantId(_)) => {
588 // this is only really valid for unit variants, but
589 // shadowing other enum variants with a pattern is
590 // an error anyway
591 Pat::Path(name.into())
592 }
593 Some(ModuleDefId::AdtId(AdtId::StructId(s)))
594 if self.db.struct_data(s).variant_data.kind() != StructKind::Record =>
595 {
596 // Funnily enough, record structs *can* be shadowed
597 // by pattern bindings (but unit or tuple structs
598 // can't).
599 Pat::Path(name.into())
600 }
601 // shadowing statics is an error as well, so we just ignore that case here
602 _ => Pat::Bind { name, mode: annotation, subpat },
603 }
604 } else {
605 Pat::Bind { name, mode: annotation, subpat }
606 }
575 } 607 }
576 ast::Pat::TupleStructPat(p) => { 608 ast::Pat::TupleStructPat(p) => {
577 let path = p.path().and_then(|path| self.expander.parse_path(path)); 609 let path = p.path().and_then(|path| self.expander.parse_path(path));
diff --git a/crates/ra_hir_def/src/expr.rs b/crates/ra_hir_def/src/expr.rs
index 9707c5527..66d004717 100644
--- a/crates/ra_hir_def/src/expr.rs
+++ b/crates/ra_hir_def/src/expr.rs
@@ -48,7 +48,7 @@ pub enum Literal {
48 48
49#[derive(Debug, Clone, Eq, PartialEq)] 49#[derive(Debug, Clone, Eq, PartialEq)]
50pub enum Expr { 50pub enum Expr {
51 /// This is produced if syntax tree does not have a required expression piece. 51 /// This is produced if the syntax tree does not have a required expression piece.
52 Missing, 52 Missing,
53 Path(Path), 53 Path(Path),
54 If { 54 If {
diff --git a/crates/ra_hir_ty/src/infer/pat.rs b/crates/ra_hir_ty/src/infer/pat.rs
index a495ecbfe..bf8ea192b 100644
--- a/crates/ra_hir_ty/src/infer/pat.rs
+++ b/crates/ra_hir_ty/src/infer/pat.rs
@@ -189,7 +189,9 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
189 }; 189 };
190 // use a new type variable if we got Ty::Unknown here 190 // use a new type variable if we got Ty::Unknown here
191 let ty = self.insert_type_vars_shallow(ty); 191 let ty = self.insert_type_vars_shallow(ty);
192 self.unify(&ty, expected); 192 if !self.unify(&ty, expected) {
193 // FIXME record mismatch, we need to change the type of self.type_mismatches for that
194 }
193 let ty = self.resolve_ty_as_possible(ty); 195 let ty = self.resolve_ty_as_possible(ty);
194 self.write_pat_ty(pat, ty.clone()); 196 self.write_pat_ty(pat, ty.clone());
195 ty 197 ty
diff --git a/crates/ra_hir_ty/src/tests/patterns.rs b/crates/ra_hir_ty/src/tests/patterns.rs
index e25d6dbc4..81d00c2af 100644
--- a/crates/ra_hir_ty/src/tests/patterns.rs
+++ b/crates/ra_hir_ty/src/tests/patterns.rs
@@ -1,4 +1,4 @@
1use super::infer; 1use super::{infer, infer_with_mismatches};
2use insta::assert_snapshot; 2use insta::assert_snapshot;
3use test_utils::covers; 3use test_utils::covers;
4 4
@@ -236,3 +236,47 @@ fn test(a1: A<u32>, o: Option<u64>) {
236 "### 236 "###
237 ); 237 );
238} 238}
239
240#[test]
241fn infer_const_pattern() {
242 assert_snapshot!(
243 infer_with_mismatches(r#"
244enum Option<T> { None }
245use Option::None;
246struct Foo;
247const Bar: usize = 1;
248
249fn test() {
250 let a: Option<u32> = None;
251 let b: Option<i64> = match a {
252 None => None,
253 };
254 let _: () = match () { Foo => Foo }; // Expected mismatch
255 let _: () = match () { Bar => Bar }; // Expected mismatch
256}
257"#, true),
258 @r###"
259 [74; 75) '1': usize
260 [88; 310) '{ ...atch }': ()
261 [98; 99) 'a': Option<u32>
262 [115; 119) 'None': Option<u32>
263 [129; 130) 'b': Option<i64>
264 [146; 183) 'match ... }': Option<i64>
265 [152; 153) 'a': Option<u32>
266 [164; 168) 'None': Option<u32>
267 [172; 176) 'None': Option<i64>
268 [193; 194) '_': ()
269 [201; 224) 'match ... Foo }': Foo
270 [207; 209) '()': ()
271 [212; 215) 'Foo': Foo
272 [219; 222) 'Foo': Foo
273 [255; 256) '_': ()
274 [263; 286) 'match ... Bar }': usize
275 [269; 271) '()': ()
276 [274; 277) 'Bar': usize
277 [281; 284) 'Bar': usize
278 [201; 224): expected (), got Foo
279 [263; 286): expected (), got usize
280 "###
281 );
282}