use test_utils::tested_by;
use crate::{
+ adt::StructKind,
body::{Body, BodySourceMap, Expander, PatPtr},
builtin_type::{BuiltinFloat, BuiltinInt},
db::DefDatabase,
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(
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));
-use super::infer;
+use super::{infer, infer_with_mismatches};
use insta::assert_snapshot;
use test_utils::covers;
"###
);
}
+
+#[test]
+fn infer_const_pattern() {
+ assert_snapshot!(
+ infer_with_mismatches(r#"
+enum Option<T> { None }
+use Option::None;
+struct Foo;
+const Bar: usize = 1;
+
+fn test() {
+ let a: Option<u32> = None;
+ let b: Option<i64> = match a {
+ None => None,
+ };
+ let _: () = match () { Foo => Foo }; // Expected mismatch
+ let _: () = match () { Bar => Bar }; // Expected mismatch
+}
+"#, true),
+ @r###"
+ [74; 75) '1': usize
+ [88; 310) '{ ...atch }': ()
+ [98; 99) 'a': Option<u32>
+ [115; 119) 'None': Option<u32>
+ [129; 130) 'b': Option<i64>
+ [146; 183) 'match ... }': Option<i64>
+ [152; 153) 'a': Option<u32>
+ [164; 168) 'None': Option<u32>
+ [172; 176) 'None': Option<i64>
+ [193; 194) '_': ()
+ [201; 224) 'match ... Foo }': Foo
+ [207; 209) '()': ()
+ [212; 215) 'Foo': Foo
+ [219; 222) 'Foo': Foo
+ [255; 256) '_': ()
+ [263; 286) 'match ... Bar }': usize
+ [269; 271) '()': ()
+ [274; 277) 'Bar': usize
+ [281; 284) 'Bar': usize
+ [201; 224): expected (), got Foo
+ [263; 286): expected (), got usize
+ "###
+ );
+}