about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_borrowck/src/type_check/mod.rs64
-rw-r--r--compiler/rustc_mir_build/src/build/matches/simplify.rs37
-rw-r--r--tests/ui/inline-const/const-match-pat-lifetime-err.rs25
-rw-r--r--tests/ui/inline-const/const-match-pat-lifetime-err.stderr28
-rw-r--r--tests/ui/inline-const/pat-unsafe-err.rs2
-rw-r--r--tests/ui/inline-const/pat-unsafe-err.stderr19
-rw-r--r--tests/ui/inline-const/pat-unsafe.rs1
-rw-r--r--tests/ui/inline-const/pat-unsafe.stderr20
8 files changed, 178 insertions, 18 deletions
diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs
index cf28e62177f..488dfc64cf6 100644
--- a/compiler/rustc_borrowck/src/type_check/mod.rs
+++ b/compiler/rustc_borrowck/src/type_check/mod.rs
@@ -1099,10 +1099,17 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
     #[instrument(skip(self), level = "debug")]
     fn check_user_type_annotations(&mut self) {
         debug!(?self.user_type_annotations);
+        let tcx = self.tcx();
         for user_annotation in self.user_type_annotations {
             let CanonicalUserTypeAnnotation { span, ref user_ty, inferred_ty } = *user_annotation;
             let annotation = self.instantiate_canonical_with_fresh_inference_vars(span, user_ty);
-            self.ascribe_user_type(inferred_ty, annotation, span);
+            if let ty::UserType::TypeOf(def, args) = annotation
+                && let DefKind::InlineConst = tcx.def_kind(def)
+            {
+                self.check_inline_const(inferred_ty, def.expect_local(), args, span);
+            } else {
+                self.ascribe_user_type(inferred_ty, annotation, span);
+            }
         }
     }
 
@@ -1195,6 +1202,36 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
         Ok(())
     }
 
+    fn check_inline_const(
+        &mut self,
+        inferred_ty: Ty<'tcx>,
+        def_id: LocalDefId,
+        args: UserArgs<'tcx>,
+        span: Span,
+    ) {
+        assert!(args.user_self_ty.is_none());
+        let tcx = self.tcx();
+        let const_ty = tcx.type_of(def_id).instantiate(tcx, args.args);
+        if let Err(terr) =
+            self.eq_types(const_ty, inferred_ty, Locations::All(span), ConstraintCategory::Boring)
+        {
+            span_bug!(
+                span,
+                "bad inline const pattern: ({:?} = {:?}) {:?}",
+                const_ty,
+                inferred_ty,
+                terr
+            );
+        }
+        let args = self.infcx.resolve_vars_if_possible(args.args);
+        let predicates = self.prove_closure_bounds(tcx, def_id, args, Locations::All(span));
+        self.normalize_and_prove_instantiated_predicates(
+            def_id.to_def_id(),
+            predicates,
+            Locations::All(span),
+        );
+    }
+
     fn tcx(&self) -> TyCtxt<'tcx> {
         self.infcx.tcx
     }
@@ -1851,7 +1888,12 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
                     let def_id = uv.def;
                     if tcx.def_kind(def_id) == DefKind::InlineConst {
                         let def_id = def_id.expect_local();
-                        let predicates = self.prove_closure_bounds(tcx, def_id, uv.args, location);
+                        let predicates = self.prove_closure_bounds(
+                            tcx,
+                            def_id,
+                            uv.args,
+                            location.to_locations(),
+                        );
                         self.normalize_and_prove_instantiated_predicates(
                             def_id.to_def_id(),
                             predicates,
@@ -2654,9 +2696,15 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
             // desugaring. A closure gets desugared to a struct, and
             // these extra requirements are basically like where
             // clauses on the struct.
-            AggregateKind::Closure(def_id, args) | AggregateKind::Coroutine(def_id, args) => {
-                (def_id, self.prove_closure_bounds(tcx, def_id.expect_local(), args, location))
-            }
+            AggregateKind::Closure(def_id, args) | AggregateKind::Coroutine(def_id, args) => (
+                def_id,
+                self.prove_closure_bounds(
+                    tcx,
+                    def_id.expect_local(),
+                    args,
+                    location.to_locations(),
+                ),
+            ),
 
             AggregateKind::Array(_) | AggregateKind::Tuple => {
                 (CRATE_DEF_ID.to_def_id(), ty::InstantiatedPredicates::empty())
@@ -2675,7 +2723,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
         tcx: TyCtxt<'tcx>,
         def_id: LocalDefId,
         args: GenericArgsRef<'tcx>,
-        location: Location,
+        locations: Locations,
     ) -> ty::InstantiatedPredicates<'tcx> {
         if let Some(closure_requirements) = &tcx.mir_borrowck(def_id).closure_requirements {
             constraint_conversion::ConstraintConversion::new(
@@ -2684,7 +2732,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
                 self.region_bound_pairs,
                 self.implicit_region_bound,
                 self.param_env,
-                location.to_locations(),
+                locations,
                 DUMMY_SP,                   // irrelevant; will be overridden.
                 ConstraintCategory::Boring, // same as above.
                 self.borrowck_context.constraints,
@@ -2710,7 +2758,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
         if let Err(_) = self.eq_args(
             typeck_root_args,
             parent_args,
-            location.to_locations(),
+            locations,
             ConstraintCategory::BoringNoLocation,
         ) {
             span_mirbug!(
diff --git a/compiler/rustc_mir_build/src/build/matches/simplify.rs b/compiler/rustc_mir_build/src/build/matches/simplify.rs
index a7f6f4873e3..065c93e86a8 100644
--- a/compiler/rustc_mir_build/src/build/matches/simplify.rs
+++ b/compiler/rustc_mir_build/src/build/matches/simplify.rs
@@ -15,7 +15,9 @@
 use crate::build::expr::as_place::PlaceBuilder;
 use crate::build::matches::{Ascription, Binding, Candidate, MatchPair};
 use crate::build::Builder;
+use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
 use rustc_middle::thir::{self, *};
+use rustc_middle::ty;
 
 use std::mem;
 
@@ -149,7 +151,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 ref subpattern,
                 ascription: thir::Ascription { ref annotation, variance },
             } => {
-                // Apply the type ascription to the value at `match_pair.place`, which is the
+                // Apply the type ascription to the value at `match_pair.place`
                 if let Some(source) = match_pair.place.try_to_place(self) {
                     candidate.ascriptions.push(Ascription {
                         annotation: annotation.clone(),
@@ -205,7 +207,38 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 Err(match_pair)
             }
 
-            PatKind::InlineConstant { subpattern: ref pattern, def: _ } => {
+            PatKind::InlineConstant { subpattern: ref pattern, def } => {
+                // Apply a type ascription for the inline constant to the value at `match_pair.place`
+                if let Some(source) = match_pair.place.try_to_place(self) {
+                    let span = match_pair.pattern.span;
+                    let parent_id = self.tcx.typeck_root_def_id(self.def_id.to_def_id());
+                    let args = ty::InlineConstArgs::new(
+                        self.tcx,
+                        ty::InlineConstArgsParts {
+                            parent_args: ty::GenericArgs::identity_for_item(self.tcx, parent_id),
+                            ty: self.infcx.next_ty_var(TypeVariableOrigin {
+                                kind: TypeVariableOriginKind::MiscVariable,
+                                span,
+                            }),
+                        },
+                    )
+                    .args;
+                    let user_ty =
+                        self.infcx.canonicalize_user_type_annotation(ty::UserType::TypeOf(
+                            def.to_def_id(),
+                            ty::UserArgs { args, user_self_ty: None },
+                        ));
+                    let annotation = ty::CanonicalUserTypeAnnotation {
+                        inferred_ty: pattern.ty,
+                        span,
+                        user_ty: Box::new(user_ty),
+                    };
+                    candidate.ascriptions.push(Ascription {
+                        annotation,
+                        source,
+                        variance: ty::Contravariant,
+                    });
+                }
                 candidate.match_pairs.push(MatchPair::new(match_pair.place, pattern, self));
 
                 Ok(())
diff --git a/tests/ui/inline-const/const-match-pat-lifetime-err.rs b/tests/ui/inline-const/const-match-pat-lifetime-err.rs
index 366ad26bb27..ce91e5233bc 100644
--- a/tests/ui/inline-const/const-match-pat-lifetime-err.rs
+++ b/tests/ui/inline-const/const-match-pat-lifetime-err.rs
@@ -1,5 +1,3 @@
-// ignore-test (This is currently broken)
-
 #![allow(incomplete_features)]
 #![feature(const_mut_refs)]
 #![feature(inline_const_pat)]
@@ -9,6 +7,9 @@ use std::marker::PhantomData;
 #[derive(PartialEq, Eq)]
 pub struct InvariantRef<'a, T: ?Sized>(&'a T, PhantomData<&'a mut &'a T>);
 
+#[derive(PartialEq, Eq)]
+pub struct CovariantRef<'a, T: ?Sized>(&'a T);
+
 impl<'a, T: ?Sized> InvariantRef<'a, T> {
     pub const fn new(r: &'a T) -> Self {
         InvariantRef(r, PhantomData)
@@ -19,16 +20,30 @@ impl<'a> InvariantRef<'a, ()> {
     pub const NEW: Self = InvariantRef::new(&());
 }
 
+impl<'a> CovariantRef<'a, ()> {
+    pub const NEW: Self = CovariantRef(&());
+}
+
 fn match_invariant_ref<'a>() {
     let y = ();
     match InvariantRef::new(&y) {
-    //~^ ERROR `y` does not live long enough [E0597]
-        // FIXME(nbdd0121): This should give the same error as `InvariantRef::<'a>::NEW` (without
-        // const block)
+        //~^ ERROR `y` does not live long enough [E0597]
         const { InvariantRef::<'a>::NEW } => (),
     }
 }
 
+fn match_covariant_ref<'a>() {
+    // Unclear if we should error here (should we be able to subtype the type of
+    // `y.0`), but using the associated const directly in the pattern also
+    // errors.
+    let y: (CovariantRef<'static, _>,) = (CovariantRef(&()),);
+    //~^ ERROR lifetime may not live long enough
+    match y.0 {
+        const { CovariantRef::<'a>::NEW } => (),
+    }
+}
+
 fn main() {
     match_invariant_ref();
+    match_covariant_ref();
 }
diff --git a/tests/ui/inline-const/const-match-pat-lifetime-err.stderr b/tests/ui/inline-const/const-match-pat-lifetime-err.stderr
new file mode 100644
index 00000000000..c5760f1027e
--- /dev/null
+++ b/tests/ui/inline-const/const-match-pat-lifetime-err.stderr
@@ -0,0 +1,28 @@
+error[E0597]: `y` does not live long enough
+  --> $DIR/const-match-pat-lifetime-err.rs:29:29
+   |
+LL | fn match_invariant_ref<'a>() {
+   |                        -- lifetime `'a` defined here
+LL |     let y = ();
+   |         - binding `y` declared here
+LL |     match InvariantRef::new(&y) {
+   |                             ^^ borrowed value does not live long enough
+LL |
+LL |         const { InvariantRef::<'a>::NEW } => (),
+   |         --------------------------------- type annotation requires that `y` is borrowed for `'a`
+LL |     }
+LL | }
+   | - `y` dropped here while still borrowed
+
+error: lifetime may not live long enough
+  --> $DIR/const-match-pat-lifetime-err.rs:39:12
+   |
+LL | fn match_covariant_ref<'a>() {
+   |                        -- lifetime `'a` defined here
+...
+LL |     let y: (CovariantRef<'static, _>,) = (CovariantRef(&()),);
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'static`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0597`.
diff --git a/tests/ui/inline-const/pat-unsafe-err.rs b/tests/ui/inline-const/pat-unsafe-err.rs
index 0db18dd3260..7680c82efb5 100644
--- a/tests/ui/inline-const/pat-unsafe-err.rs
+++ b/tests/ui/inline-const/pat-unsafe-err.rs
@@ -1,5 +1,3 @@
-// ignore-test This is currently broken
-
 #![allow(incomplete_features)]
 #![feature(inline_const_pat)]
 
diff --git a/tests/ui/inline-const/pat-unsafe-err.stderr b/tests/ui/inline-const/pat-unsafe-err.stderr
new file mode 100644
index 00000000000..9b995d6ccf2
--- /dev/null
+++ b/tests/ui/inline-const/pat-unsafe-err.stderr
@@ -0,0 +1,19 @@
+error[E0133]: call to unsafe function `require_unsafe` is unsafe and requires unsafe function or block
+  --> $DIR/pat-unsafe-err.rs:11:13
+   |
+LL |             require_unsafe();
+   |             ^^^^^^^^^^^^^^^^ call to unsafe function
+   |
+   = note: consult the function's documentation for information on how to avoid undefined behavior
+
+error[E0133]: call to unsafe function `require_unsafe` is unsafe and requires unsafe function or block
+  --> $DIR/pat-unsafe-err.rs:18:13
+   |
+LL |             require_unsafe()
+   |             ^^^^^^^^^^^^^^^^ call to unsafe function
+   |
+   = note: consult the function's documentation for information on how to avoid undefined behavior
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0133`.
diff --git a/tests/ui/inline-const/pat-unsafe.rs b/tests/ui/inline-const/pat-unsafe.rs
index cfef9ad6a56..f7073ef40eb 100644
--- a/tests/ui/inline-const/pat-unsafe.rs
+++ b/tests/ui/inline-const/pat-unsafe.rs
@@ -1,5 +1,4 @@
 // check-pass
-// ignore-test This is currently broken
 
 #![allow(incomplete_features)]
 #![warn(unused_unsafe)]
diff --git a/tests/ui/inline-const/pat-unsafe.stderr b/tests/ui/inline-const/pat-unsafe.stderr
new file mode 100644
index 00000000000..84dc10c4902
--- /dev/null
+++ b/tests/ui/inline-const/pat-unsafe.stderr
@@ -0,0 +1,20 @@
+warning: unnecessary `unsafe` block
+  --> $DIR/pat-unsafe.rs:16:17
+   |
+LL |                 unsafe {}
+   |                 ^^^^^^ unnecessary `unsafe` block
+   |
+note: the lint level is defined here
+  --> $DIR/pat-unsafe.rs:4:9
+   |
+LL | #![warn(unused_unsafe)]
+   |         ^^^^^^^^^^^^^
+
+warning: unnecessary `unsafe` block
+  --> $DIR/pat-unsafe.rs:23:17
+   |
+LL |                 unsafe {}
+   |                 ^^^^^^ unnecessary `unsafe` block
+
+warning: 2 warnings emitted
+