..
},
user_ty: pat_ascription_ty,
+ variance: _,
user_ty_span,
} => {
let place =
source_info: ty_source_info,
kind: StatementKind::AscribeUserType(
place,
+ // We always use invariant as the variance here. This is because the
+ // variance field from the ascription refers to the variance to use
+ // when applying the type to the value being matched, but this
+ // ascription applies rather to the type of the binding. e.g., in this
+ // example:
+ //
+ // ```
+ // let x: T = <expr>
+ // ```
+ //
+ // We are creating an ascription that defines the type of `x` to be
+ // exactly `T` (i.e., with invariance). The variance field, in
+ // contrast, is intended to be used to relate `T` to the type of
+ // `<expr>`.
ty::Variance::Invariant,
user_ty,
),
PatternKind::Deref { ref subpattern } => {
self.visit_bindings(subpattern, pattern_user_ty.deref(), f);
}
- PatternKind::AscribeUserType { ref subpattern, ref user_ty, user_ty_span } => {
+ PatternKind::AscribeUserType {
+ ref subpattern,
+ ref user_ty,
+ user_ty_span,
+ variance: _,
+ } => {
// This corresponds to something like
//
// ```
// let A::<'a>(_): A<'static> = ...;
// ```
+ //
+ // Note that the variance doesn't apply here, as we are tracking the effect
+ // of `user_ty` on any bindings contained with subpattern.
let annotation = (user_ty_span, user_ty.base);
let projection = UserTypeProjection {
base: self.canonical_user_type_annotations.push(annotation),
span: Span,
source: Place<'tcx>,
user_ty: PatternTypeProjection<'tcx>,
+ variance: ty::Variance,
}
#[derive(Clone, Debug)]
source_info,
kind: StatementKind::AscribeUserType(
ascription.source.clone(),
- ty::Variance::Covariant,
+ ascription.variance,
user_ty,
),
},
-> Result<(), MatchPair<'pat, 'tcx>> {
let tcx = self.hir.tcx();
match *match_pair.pattern.kind {
- PatternKind::AscribeUserType { ref subpattern, ref user_ty, user_ty_span } => {
+ PatternKind::AscribeUserType {
+ ref subpattern,
+ variance,
+ ref user_ty,
+ user_ty_span
+ } => {
+ // Apply the type ascription to the value at `match_pair.place`, which is the
+ // value being matched, taking the variance field into account.
candidate.ascriptions.push(Ascription {
span: user_ty_span,
user_ty: user_ty.clone(),
source: match_pair.place.clone(),
+ variance,
});
candidate.match_pairs.push(MatchPair::new(match_pair.place, subpattern));
use hair::cx::to_ref::ToRef;
use rustc::middle::region;
use rustc::hir;
+use rustc::ty;
use rustc_data_structures::indexed_vec::Idx;
kind: Box::new(PatternKind::AscribeUserType {
user_ty: PatternTypeProjection::from_user_type(user_ty),
user_ty_span: ty.span,
- subpattern: pattern
+ subpattern: pattern,
+ variance: ty::Variance::Covariant,
})
};
}
AscribeUserType {
user_ty: PatternTypeProjection<'tcx>,
subpattern: Pattern<'tcx>,
+ /// Variance to use when relating the type `user_ty` to the **type of the value being
+ /// matched**. Typically, this is `Variance::Covariant`, since the value being matched must
+ /// have a type that is some subtype of the ascribed type.
+ ///
+ /// Note that this variance does not apply for any bindings within subpatterns. The type
+ /// assigned to those bindings must be exactly equal to the `user_ty` given here.
+ ///
+ /// The only place where this field is not `Covariant` is when matching constants, where
+ /// we currently use `Contravariant` -- this is because the constant type just needs to
+ /// be "comparable" to the type of the input value. So, for example:
+ ///
+ /// ```text
+ /// match x { "foo" => .. }
+ /// ```
+ ///
+ /// requires that `&'static str <: T_x`, where `T_x` is the type of `x`. Really, we should
+ /// probably be checking for a `PartialEq` impl instead, but this preserves the behavior
+ /// of the old type-check for now. See #57280 for details.
+ variance: ty::Variance,
user_ty_span: Span,
},
},
user_ty: PatternTypeProjection::from_user_type(user_ty),
user_ty_span: span,
+ variance: ty::Variance::Covariant,
};
}
kind: Box::new(
PatternKind::AscribeUserType {
subpattern: pattern,
+ /// Note that use `Contravariant` here. See the
+ /// `variance` field documentation for details.
+ variance: ty::Variance::Contravariant,
user_ty,
user_ty_span: span,
}
PatternKind::Wild => PatternKind::Wild,
PatternKind::AscribeUserType {
ref subpattern,
+ variance,
ref user_ty,
user_ty_span,
} => PatternKind::AscribeUserType {
subpattern: subpattern.fold_with(folder),
user_ty: user_ty.fold_with(folder),
+ variance,
user_ty_span,
},
PatternKind::Binding {
--- /dev/null
+#![feature(nll)]
+
+// compile-pass
+
+trait Foo<'a> {
+ const C: &'a u32;
+}
+
+impl<'a, T> Foo<'a> for T {
+ const C: &'a u32 = &22;
+}
+
+fn foo() {
+ let a = 22;
+ match &a {
+ <() as Foo<'static>>::C => { }
+ &_ => { }
+ }
+}
+
+fn main() {}
--- /dev/null
+#![feature(nll)]
+
+// compile-pass
+
+trait Foo {
+ const BLAH: &'static str;
+}
+
+struct Placeholder;
+
+impl Foo for Placeholder {
+ const BLAH: &'static str = "hi";
+}
+
+fn foo(x: &str) {
+ match x {
+ <Placeholder as Foo>::BLAH => { }
+ _ => { }
+ }
+}
+
+fn main() {}