about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_hir_analysis/src/collect/item_bounds.rs2
-rw-r--r--compiler/rustc_middle/src/ty/print/pretty.rs26
-rw-r--r--compiler/rustc_query_impl/src/plumbing.rs15
-rw-r--r--compiler/rustc_resolve/messages.ftl7
-rw-r--r--compiler/rustc_resolve/src/diagnostics.rs23
-rw-r--r--compiler/rustc_resolve/src/errors.rs15
-rw-r--r--compiler/rustc_trait_selection/src/lib.rs1
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs29
-rw-r--r--tests/ui/macros/defined-later-issue-121061-2.rs13
-rw-r--r--tests/ui/macros/defined-later-issue-121061-2.stderr14
-rw-r--r--tests/ui/macros/defined-later-issue-121061.rs9
-rw-r--r--tests/ui/macros/defined-later-issue-121061.stderr14
-rw-r--r--tests/ui/typeck/method-chain-gats.rs22
-rw-r--r--tests/ui/typeck/method-chain-gats.stderr27
14 files changed, 180 insertions, 37 deletions
diff --git a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs
index 39ca1bba065..78c390d0924 100644
--- a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs
+++ b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs
@@ -64,7 +64,7 @@ fn opaque_type_bounds<'tcx>(
     item_ty: Ty<'tcx>,
     span: Span,
 ) -> &'tcx [(ty::Clause<'tcx>, Span)] {
-    ty::print::with_no_queries!({
+    ty::print::with_reduced_queries!({
         let icx = ItemCtxt::new(tcx, opaque_def_id);
         let mut bounds = icx.astconv().compute_bounds(item_ty, ast_bounds, PredicateFilter::All);
         // Opaque types are implicitly sized unless a `?Sized` bound is found
diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs
index bbe06c09352..540803d9530 100644
--- a/compiler/rustc_middle/src/ty/print/pretty.rs
+++ b/compiler/rustc_middle/src/ty/print/pretty.rs
@@ -64,7 +64,7 @@ thread_local! {
     static SHOULD_PREFIX_WITH_CRATE: Cell<bool> = const { Cell::new(false) };
     static NO_TRIMMED_PATH: Cell<bool> = const { Cell::new(false) };
     static FORCE_TRIMMED_PATH: Cell<bool> = const { Cell::new(false) };
-    static NO_QUERIES: Cell<bool> = const { Cell::new(false) };
+    static REDUCED_QUERIES: Cell<bool> = const { Cell::new(false) };
     static NO_VISIBLE_PATH: Cell<bool> = const { Cell::new(false) };
 }
 
@@ -102,14 +102,14 @@ macro_rules! define_helper {
 }
 
 define_helper!(
-    /// Avoids running any queries during any prints that occur
+    /// Avoids running select queries during any prints that occur
     /// during the closure. This may alter the appearance of some
     /// types (e.g. forcing verbose printing for opaque types).
     /// This method is used during some queries (e.g. `explicit_item_bounds`
     /// for opaque types), to ensure that any debug printing that
     /// occurs during the query computation does not end up recursively
     /// calling the same query.
-    fn with_no_queries(NoQueriesGuard, NO_QUERIES);
+    fn with_reduced_queries(ReducedQueriesGuard, REDUCED_QUERIES);
     /// Force us to name impls with just the filename/line number. We
     /// normally try to use types. But at some points, notably while printing
     /// cycle errors, this can result in extra or suboptimal error output,
@@ -127,6 +127,15 @@ define_helper!(
     fn with_no_visible_paths(NoVisibleGuard, NO_VISIBLE_PATH);
 );
 
+/// Avoids running any queries during prints.
+pub macro with_no_queries($e:expr) {{
+    $crate::ty::print::with_reduced_queries!($crate::ty::print::with_forced_impl_filename_line!(
+        $crate::ty::print::with_no_trimmed_paths!($crate::ty::print::with_no_visible_paths!(
+            $crate::ty::print::with_forced_impl_filename_line!($e)
+        ))
+    ))
+}}
+
 /// The "region highlights" are used to control region printing during
 /// specific error messages. When a "region highlight" is enabled, it
 /// gives an alternate way to print specific regions. For now, we
@@ -659,7 +668,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
                 p!(")")
             }
             ty::FnDef(def_id, args) => {
-                if with_no_queries() {
+                if with_reduced_queries() {
                     p!(print_def_path(def_id, args));
                 } else {
                     let sig = self.tcx().fn_sig(def_id).instantiate(self.tcx(), args);
@@ -759,7 +768,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
                         return Ok(());
                     }
                     _ => {
-                        if with_no_queries() {
+                        if with_reduced_queries() {
                             p!(print_def_path(def_id, &[]));
                             return Ok(());
                         } else {
@@ -1876,7 +1885,8 @@ impl DerefMut for FmtPrinter<'_, '_> {
 
 impl<'a, 'tcx> FmtPrinter<'a, 'tcx> {
     pub fn new(tcx: TyCtxt<'tcx>, ns: Namespace) -> Self {
-        let limit = if with_no_queries() { Limit::new(1048576) } else { tcx.type_length_limit() };
+        let limit =
+            if with_reduced_queries() { Limit::new(1048576) } else { tcx.type_length_limit() };
         Self::new_with_limit(tcx, ns, limit)
     }
 
@@ -2962,7 +2972,7 @@ define_print_and_forward_display! {
     }
 
     TraitRefPrintSugared<'tcx> {
-        if !with_no_queries()
+        if !with_reduced_queries()
             && let Some(kind) = cx.tcx().fn_trait_kind_from_def_id(self.0.def_id)
             && let ty::Tuple(args) = self.0.args.type_at(1).kind()
         {
@@ -3050,7 +3060,7 @@ define_print_and_forward_display! {
             // If we're printing verbosely, or don't want to invoke queries
             // (`is_impl_trait_in_trait`), then fall back to printing the def path.
             // This is likely what you want if you're debugging the compiler anyways.
-            if !(cx.should_print_verbose() || with_no_queries())
+            if !(cx.should_print_verbose() || with_reduced_queries())
                 && cx.tcx().is_impl_trait_in_trait(self.def_id)
             {
                 return cx.pretty_print_opaque_impl_type(self.def_id, self.args);
diff --git a/compiler/rustc_query_impl/src/plumbing.rs b/compiler/rustc_query_impl/src/plumbing.rs
index c7baca86d93..1b546bf9103 100644
--- a/compiler/rustc_query_impl/src/plumbing.rs
+++ b/compiler/rustc_query_impl/src/plumbing.rs
@@ -18,7 +18,7 @@ use rustc_middle::query::on_disk_cache::AbsoluteBytePos;
 use rustc_middle::query::on_disk_cache::{CacheDecoder, CacheEncoder, EncodedDepNodeIndex};
 use rustc_middle::query::Key;
 use rustc_middle::ty::tls::{self, ImplicitCtxt};
-use rustc_middle::ty::{self, print::with_no_queries, TyCtxt};
+use rustc_middle::ty::{self, TyCtxt};
 use rustc_query_system::dep_graph::{DepNodeParams, HasDepContext};
 use rustc_query_system::ich::StableHashingContext;
 use rustc_query_system::query::{
@@ -305,20 +305,13 @@ pub(crate) fn create_query_frame<
     name: &'static str,
 ) -> QueryStackFrame {
     // Avoid calling queries while formatting the description
-    let description = ty::print::with_no_queries!(
-        // Disable visible paths printing for performance reasons.
-        // Showing visible path instead of any path is not that important in production.
-        ty::print::with_no_visible_paths!(
-            // Force filename-line mode to avoid invoking `type_of` query.
-            ty::print::with_forced_impl_filename_line!(do_describe(tcx, key))
-        )
-    );
+    let description = ty::print::with_no_queries!(do_describe(tcx, key));
     let description = if tcx.sess.verbose_internals() {
         format!("{description} [{name:?}]")
     } else {
         description
     };
-    let span = if kind == dep_graph::dep_kinds::def_span || with_no_queries() {
+    let span = if kind == dep_graph::dep_kinds::def_span {
         // The `def_span` query is used to calculate `default_span`,
         // so exit to avoid infinite recursion.
         None
@@ -326,7 +319,7 @@ pub(crate) fn create_query_frame<
         Some(key.default_span(tcx))
     };
     let def_id = key.key_as_def_id();
-    let def_kind = if kind == dep_graph::dep_kinds::def_kind || with_no_queries() {
+    let def_kind = if kind == dep_graph::dep_kinds::def_kind {
         // Try to avoid infinite recursion.
         None
     } else {
diff --git a/compiler/rustc_resolve/messages.ftl b/compiler/rustc_resolve/messages.ftl
index fa98338bbb6..a03bb6acd41 100644
--- a/compiler/rustc_resolve/messages.ftl
+++ b/compiler/rustc_resolve/messages.ftl
@@ -83,6 +83,10 @@ resolve_consider_declaring_with_pub =
 resolve_consider_marking_as_pub =
     consider marking `{$ident}` as `pub` in the imported module
 
+resolve_consider_move_macro_position =
+    consider moving the definition of `{$ident}` before this call
+
+
 resolve_const_not_member_of_trait =
     const `{$const_}` is not a member of trait `{$trait_}`
     .label = not a member of trait `{$trait_}`
@@ -176,6 +180,9 @@ resolve_lowercase_self =
     attempt to use a non-constant value in a constant
     .suggestion = try using `Self`
 
+resolve_macro_defined_later =
+    a macro with the same name exists, but it appears later at here
+
 resolve_macro_expected_found =
     expected {$expected}, found {$found} `{$macro_path}`
 
diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs
index 6b45db7ba83..dc7dfa04d18 100644
--- a/compiler/rustc_resolve/src/diagnostics.rs
+++ b/compiler/rustc_resolve/src/diagnostics.rs
@@ -30,7 +30,10 @@ use rustc_span::{BytePos, Span, SyntaxContext};
 use thin_vec::{thin_vec, ThinVec};
 
 use crate::errors::{AddedMacroUse, ChangeImportBinding, ChangeImportBindingSuggestion};
-use crate::errors::{ConsiderAddingADerive, ExplicitUnsafeTraits, MaybeMissingMacroRulesName};
+use crate::errors::{
+    ConsiderAddingADerive, ExplicitUnsafeTraits, MacroDefinedLater, MacroSuggMovePosition,
+    MaybeMissingMacroRulesName,
+};
 use crate::imports::{Import, ImportKind};
 use crate::late::{PatternSource, Rib};
 use crate::{errors as errs, BindingKey};
@@ -1456,6 +1459,24 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
             return;
         }
 
+        let unused_macro = self.unused_macros.iter().find_map(|(def_id, (_, unused_ident))| {
+            if unused_ident.name == ident.name {
+                Some((def_id.clone(), unused_ident.clone()))
+            } else {
+                None
+            }
+        });
+
+        if let Some((def_id, unused_ident)) = unused_macro {
+            let scope = self.local_macro_def_scopes[&def_id];
+            let parent_nearest = parent_scope.module.nearest_parent_mod();
+            if Some(parent_nearest) == scope.opt_def_id() {
+                err.subdiagnostic(self.dcx(), MacroDefinedLater { span: unused_ident.span });
+                err.subdiagnostic(self.dcx(), MacroSuggMovePosition { span: ident.span, ident });
+                return;
+            }
+        }
+
         if self.macro_names.contains(&ident.normalize_to_macros_2_0()) {
             err.subdiagnostic(self.dcx(), AddedMacroUse);
             return;
diff --git a/compiler/rustc_resolve/src/errors.rs b/compiler/rustc_resolve/src/errors.rs
index 6f23f531996..a9f5ed9908b 100644
--- a/compiler/rustc_resolve/src/errors.rs
+++ b/compiler/rustc_resolve/src/errors.rs
@@ -647,6 +647,21 @@ pub(crate) struct ExplicitUnsafeTraits {
 }
 
 #[derive(Subdiagnostic)]
+#[note(resolve_macro_defined_later)]
+pub(crate) struct MacroDefinedLater {
+    #[primary_span]
+    pub(crate) span: Span,
+}
+
+#[derive(Subdiagnostic)]
+#[label(resolve_consider_move_macro_position)]
+pub(crate) struct MacroSuggMovePosition {
+    #[primary_span]
+    pub(crate) span: Span,
+    pub(crate) ident: Ident,
+}
+
+#[derive(Subdiagnostic)]
 #[note(resolve_missing_macro_rules_name)]
 pub(crate) struct MaybeMissingMacroRulesName {
     #[primary_span]
diff --git a/compiler/rustc_trait_selection/src/lib.rs b/compiler/rustc_trait_selection/src/lib.rs
index 00a2adccf64..7c1bfebef2c 100644
--- a/compiler/rustc_trait_selection/src/lib.rs
+++ b/compiler/rustc_trait_selection/src/lib.rs
@@ -16,6 +16,7 @@
 #![allow(internal_features)]
 #![allow(rustc::diagnostic_outside_of_impl)]
 #![allow(rustc::untranslatable_diagnostic)]
+#![feature(assert_matches)]
 #![feature(associated_type_bounds)]
 #![feature(box_patterns)]
 #![feature(control_flow_enum)]
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
index 16290c8dbca..de834b8fb64 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
@@ -38,6 +38,7 @@ use rustc_span::def_id::LocalDefId;
 use rustc_span::symbol::{kw, sym, Ident, Symbol};
 use rustc_span::{BytePos, DesugaringKind, ExpnKind, MacroKind, Span, DUMMY_SP};
 use rustc_target::spec::abi;
+use std::assert_matches::debug_assert_matches;
 use std::borrow::Cow;
 use std::iter;
 
@@ -4219,30 +4220,25 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
             };
 
             let origin = TypeVariableOrigin { kind: TypeVariableOriginKind::TypeInference, span };
-            let trait_def_id = proj.trait_def_id(self.tcx);
             // Make `Self` be equivalent to the type of the call chain
             // expression we're looking at now, so that we can tell what
             // for example `Iterator::Item` is at this point in the chain.
-            let args = GenericArgs::for_item(self.tcx, trait_def_id, |param, _| {
-                match param.kind {
-                    ty::GenericParamDefKind::Type { .. } => {
-                        if param.index == 0 {
-                            return prev_ty.into();
-                        }
-                    }
-                    ty::GenericParamDefKind::Lifetime | ty::GenericParamDefKind::Const { .. } => {}
+            let args = GenericArgs::for_item(self.tcx, proj.def_id, |param, _| {
+                if param.index == 0 {
+                    debug_assert_matches!(param.kind, ty::GenericParamDefKind::Type { .. });
+                    return prev_ty.into();
                 }
                 self.var_for_def(span, param)
             });
             // This will hold the resolved type of the associated type, if the
             // current expression implements the trait that associated type is
             // in. For example, this would be what `Iterator::Item` is here.
-            let ty_var = self.infcx.next_ty_var(origin);
+            let ty = self.infcx.next_ty_var(origin);
             // This corresponds to `<ExprTy as Iterator>::Item = _`.
             let projection = ty::Binder::dummy(ty::PredicateKind::Clause(
                 ty::ClauseKind::Projection(ty::ProjectionPredicate {
                     projection_ty: ty::AliasTy::new(self.tcx, proj.def_id, args),
-                    term: ty_var.into(),
+                    term: ty.into(),
                 }),
             ));
             let body_def_id = self.tcx.hir().enclosing_body_owner(body_id);
@@ -4254,14 +4250,15 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                 param_env,
                 projection,
             ));
-            if ocx.select_where_possible().is_empty() {
-                // `ty_var` now holds the type that `Item` is for `ExprTy`.
-                let ty_var = self.resolve_vars_if_possible(ty_var);
-                assocs_in_this_method.push(Some((span, (proj.def_id, ty_var))));
+            if ocx.select_where_possible().is_empty()
+                && let ty = self.resolve_vars_if_possible(ty)
+                && !ty.is_ty_var()
+            {
+                assocs_in_this_method.push(Some((span, (proj.def_id, ty))));
             } else {
                 // `<ExprTy as Iterator>` didn't select, so likely we've
                 // reached the end of the iterator chain, like the originating
-                // `Vec<_>`.
+                // `Vec<_>` or the `ty` couldn't be determined.
                 // Keep the space consistent for later zipping.
                 assocs_in_this_method.push(None);
             }
diff --git a/tests/ui/macros/defined-later-issue-121061-2.rs b/tests/ui/macros/defined-later-issue-121061-2.rs
new file mode 100644
index 00000000000..3db76c281ec
--- /dev/null
+++ b/tests/ui/macros/defined-later-issue-121061-2.rs
@@ -0,0 +1,13 @@
+mod demo {
+    fn hello() {
+        something_later!(); //~ ERROR cannot find macro `something_later` in this scope
+    }
+
+    macro_rules! something_later {
+        () => {
+            println!("successfully expanded!");
+        };
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/macros/defined-later-issue-121061-2.stderr b/tests/ui/macros/defined-later-issue-121061-2.stderr
new file mode 100644
index 00000000000..aa6ef338531
--- /dev/null
+++ b/tests/ui/macros/defined-later-issue-121061-2.stderr
@@ -0,0 +1,14 @@
+error: cannot find macro `something_later` in this scope
+  --> $DIR/defined-later-issue-121061-2.rs:3:9
+   |
+LL |         something_later!();
+   |         ^^^^^^^^^^^^^^^ consider moving the definition of `something_later` before this call
+   |
+note: a macro with the same name exists, but it appears later at here
+  --> $DIR/defined-later-issue-121061-2.rs:6:18
+   |
+LL |     macro_rules! something_later {
+   |                  ^^^^^^^^^^^^^^^
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/macros/defined-later-issue-121061.rs b/tests/ui/macros/defined-later-issue-121061.rs
new file mode 100644
index 00000000000..07c6d406f03
--- /dev/null
+++ b/tests/ui/macros/defined-later-issue-121061.rs
@@ -0,0 +1,9 @@
+fn main() {
+    something_later!(); //~ ERROR cannot find macro `something_later` in this scope
+}
+
+macro_rules! something_later {
+    () => {
+        println!("successfully expanded!");
+    };
+}
diff --git a/tests/ui/macros/defined-later-issue-121061.stderr b/tests/ui/macros/defined-later-issue-121061.stderr
new file mode 100644
index 00000000000..65cb53432a9
--- /dev/null
+++ b/tests/ui/macros/defined-later-issue-121061.stderr
@@ -0,0 +1,14 @@
+error: cannot find macro `something_later` in this scope
+  --> $DIR/defined-later-issue-121061.rs:2:5
+   |
+LL |     something_later!();
+   |     ^^^^^^^^^^^^^^^ consider moving the definition of `something_later` before this call
+   |
+note: a macro with the same name exists, but it appears later at here
+  --> $DIR/defined-later-issue-121061.rs:5:14
+   |
+LL | macro_rules! something_later {
+   |              ^^^^^^^^^^^^^^^
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/typeck/method-chain-gats.rs b/tests/ui/typeck/method-chain-gats.rs
new file mode 100644
index 00000000000..c7081c9a3b1
--- /dev/null
+++ b/tests/ui/typeck/method-chain-gats.rs
@@ -0,0 +1,22 @@
+// Regression test for issue #121898.
+
+trait Base {
+    type Base<B>;
+}
+
+trait Functor<A>: Base {
+    fn fmap<B>(self, f: impl Fn(A) -> B) -> Self::Base<B>
+    where
+        Self::Base<B>: Functor<B>;
+}
+
+fn fmap2<T, A, B, C>(input: T, f1: impl Fn(A) -> B, f2: impl Fn(B) -> C) -> T::Base<C>
+where
+    T: Functor<A>,
+    T::Base<B>: Functor<B, Base<C> = T::Base<C>>,
+{
+    input.fmap(f1).fmap(f2)
+    //~^ ERROR the trait bound `<T as Base>::Base<C>: Functor<C>` is not satisfied
+}
+
+fn main() {}
diff --git a/tests/ui/typeck/method-chain-gats.stderr b/tests/ui/typeck/method-chain-gats.stderr
new file mode 100644
index 00000000000..63383792214
--- /dev/null
+++ b/tests/ui/typeck/method-chain-gats.stderr
@@ -0,0 +1,27 @@
+error[E0277]: the trait bound `<T as Base>::Base<C>: Functor<C>` is not satisfied
+  --> $DIR/method-chain-gats.rs:18:20
+   |
+LL |     input.fmap(f1).fmap(f2)
+   |                    ^^^^ the trait `Functor<C>` is not implemented for `<T as Base>::Base<C>`
+   |
+note: the method call chain might not have had the expected associated types
+  --> $DIR/method-chain-gats.rs:13:29
+   |
+LL | fn fmap2<T, A, B, C>(input: T, f1: impl Fn(A) -> B, f2: impl Fn(B) -> C) -> T::Base<C>
+   |                             ^ `Base::Base` is `<T as Base>::Base<_>` here
+note: required by a bound in `Functor::fmap`
+  --> $DIR/method-chain-gats.rs:10:24
+   |
+LL |     fn fmap<B>(self, f: impl Fn(A) -> B) -> Self::Base<B>
+   |        ---- required by a bound in this associated function
+LL |     where
+LL |         Self::Base<B>: Functor<B>;
+   |                        ^^^^^^^^^^ required by this bound in `Functor::fmap`
+help: consider further restricting the associated type
+   |
+LL |     T::Base<B>: Functor<B, Base<C> = T::Base<C>>, <T as Base>::Base<C>: Functor<C>
+   |                                                 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0277`.