]> git.lizzy.rs Git - rust.git/commitdiff
Auto merge of #84112 - Dylan-DPC:rollup-tapsrzz, r=Dylan-DPC
authorbors <bors@rust-lang.org>
Mon, 12 Apr 2021 00:38:20 +0000 (00:38 +0000)
committerbors <bors@rust-lang.org>
Mon, 12 Apr 2021 00:38:20 +0000 (00:38 +0000)
Rollup of 7 pull requests

Successful merges:

 - #83669 (Issue 81508 fix)
 - #84014 (Improve trait/impl method discrepancy errors)
 - #84059 (Bump libc dependency of std to 0.2.93)
 - #84067 (clean up example on read_to_string)
 - #84079 (Improve test for `rustdoc::bare_urls` lint)
 - #84094 (Remove FixedSizeArray)
 - #84101 (rustdoc: Move crate loader to collect_intra_doc_links::early )

Failed merges:

r? `@ghost`
`@rustbot` modify labels: rollup

39 files changed:
Cargo.lock
compiler/rustc_middle/src/ty/error.rs
compiler/rustc_middle/src/ty/relate.rs
compiler/rustc_middle/src/ty/structural_impls.rs
compiler/rustc_resolve/src/late.rs
compiler/rustc_resolve/src/lib.rs
compiler/rustc_typeck/src/check/compare_method.rs
library/core/src/array/mod.rs
library/core/tests/array.rs
library/core/tests/lib.rs
library/std/Cargo.toml
library/std/src/fs.rs
library/std/src/lib.rs
src/librustdoc/core.rs
src/librustdoc/passes/collect_intra_doc_links.rs
src/librustdoc/passes/collect_intra_doc_links/early.rs [new file with mode: 0644]
src/test/rustdoc-ui/bare-urls.fixed [new file with mode: 0644]
src/test/rustdoc-ui/bare-urls.rs [new file with mode: 0644]
src/test/rustdoc-ui/bare-urls.stderr [new file with mode: 0644]
src/test/rustdoc-ui/url-improvements.rs [deleted file]
src/test/rustdoc-ui/url-improvements.stderr [deleted file]
src/test/rustdoc/intra-doc/auxiliary/empty.rs [new file with mode: 0644]
src/test/rustdoc/intra-doc/auxiliary/empty2.rs [new file with mode: 0644]
src/test/rustdoc/intra-doc/extern-crate-only-used-in-link.rs
src/test/ui/associated-types/defaults-specialization.stderr
src/test/ui/compare-method/bad-self-type.rs [new file with mode: 0644]
src/test/ui/compare-method/bad-self-type.stderr [new file with mode: 0644]
src/test/ui/compare-method/reordered-type-param.stderr
src/test/ui/impl-trait/impl-generic-mismatch-ab.stderr
src/test/ui/impl-trait/trait_type.stderr
src/test/ui/issues/issue-13033.stderr
src/test/ui/issues/issue-20225.stderr
src/test/ui/issues/issue-21332.stderr
src/test/ui/issues/issue-35869.stderr
src/test/ui/mismatched_types/E0053.stderr
src/test/ui/mismatched_types/trait-impl-fn-incompatibility.stderr
src/test/ui/resolve/issue-81508.rs [new file with mode: 0644]
src/test/ui/resolve/issue-81508.stderr [new file with mode: 0644]
src/test/ui/wrong-mul-method-signature.stderr

index e892d87245ca7f245510b6fb113adb47b4e32ba8..ac7a1a5c3e93971d851474debd06c7dead8cc92c 100644 (file)
@@ -1909,9 +1909,9 @@ checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55"
 
 [[package]]
 name = "libc"
-version = "0.2.88"
+version = "0.2.93"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "03b07a082330a35e43f63177cc01689da34fbffa0105e1246cf0311472cac73a"
+checksum = "9385f66bf6105b241aa65a61cb923ef20efc665cb9f9bb50ac2f0c4b7f378d41"
 dependencies = [
  "rustc-std-workspace-core",
 ]
index d295b17d902aa4c6f5cf26ad22287f5dae0aaf66..008e6d015e879e2068c78cc80dbbe19bf1168b6e 100644 (file)
@@ -36,6 +36,7 @@ pub enum TypeError<'tcx> {
     UnsafetyMismatch(ExpectedFound<hir::Unsafety>),
     AbiMismatch(ExpectedFound<abi::Abi>),
     Mutability,
+    ArgumentMutability(usize),
     TupleSize(ExpectedFound<usize>),
     FixedArraySize(ExpectedFound<u64>),
     ArgCount,
@@ -46,6 +47,7 @@ pub enum TypeError<'tcx> {
     RegionsPlaceholderMismatch,
 
     Sorts(ExpectedFound<Ty<'tcx>>),
+    ArgumentSorts(ExpectedFound<Ty<'tcx>>, usize),
     IntMismatch(ExpectedFound<ty::IntVarValue>),
     FloatMismatch(ExpectedFound<ty::FloatTy>),
     Traits(ExpectedFound<DefId>),
@@ -110,7 +112,7 @@ fn report_maybe_different(
             AbiMismatch(values) => {
                 write!(f, "expected {} fn, found {} fn", values.expected, values.found)
             }
-            Mutability => write!(f, "types differ in mutability"),
+            ArgumentMutability(_) | Mutability => write!(f, "types differ in mutability"),
             TupleSize(values) => write!(
                 f,
                 "expected a tuple with {} element{}, \
@@ -142,7 +144,7 @@ fn report_maybe_different(
                 br_string(br)
             ),
             RegionsPlaceholderMismatch => write!(f, "one type is more general than the other"),
-            Sorts(values) => ty::tls::with(|tcx| {
+            ArgumentSorts(values, _) | Sorts(values) => ty::tls::with(|tcx| {
                 report_maybe_different(
                     f,
                     &values.expected.sort_string(tcx),
@@ -199,10 +201,11 @@ pub fn must_include_note(&self) -> bool {
         use self::TypeError::*;
         match self {
             CyclicTy(_) | CyclicConst(_) | UnsafetyMismatch(_) | Mismatch | AbiMismatch(_)
-            | FixedArraySize(_) | Sorts(_) | IntMismatch(_) | FloatMismatch(_)
-            | VariadicMismatch(_) | TargetFeatureCast(_) => false,
+            | FixedArraySize(_) | ArgumentSorts(..) | Sorts(_) | IntMismatch(_)
+            | FloatMismatch(_) | VariadicMismatch(_) | TargetFeatureCast(_) => false,
 
             Mutability
+            | ArgumentMutability(_)
             | TupleSize(_)
             | ArgCount
             | RegionsDoesNotOutlive(..)
@@ -339,7 +342,7 @@ pub fn note_and_explain_type_err(
         use self::TypeError::*;
         debug!("note_and_explain_type_err err={:?} cause={:?}", err, cause);
         match err {
-            Sorts(values) => {
+            ArgumentSorts(values, _) | Sorts(values) => {
                 match (values.expected.kind(), values.found.kind()) {
                     (ty::Closure(..), ty::Closure(..)) => {
                         db.note("no two closures, even if identical, have the same type");
index ca60339da0d00b9d138030dcf8c444994e52eba8..b6f93c9bd59e79bbe51efb25aefa106fdcea6e10 100644 (file)
@@ -179,6 +179,12 @@ fn relate<R: TypeRelation<'tcx>>(
                 } else {
                     relation.relate_with_variance(ty::Contravariant, a, b)
                 }
+            })
+            .enumerate()
+            .map(|(i, r)| match r {
+                Err(TypeError::Sorts(exp_found)) => Err(TypeError::ArgumentSorts(exp_found, i)),
+                Err(TypeError::Mutability) => Err(TypeError::ArgumentMutability(i)),
+                r => r,
             });
         Ok(ty::FnSig {
             inputs_and_output: tcx.mk_type_list(inputs_and_output)?,
index a969626b370f5d2dc6320f245d05112343aa60e8..7290c41d615dfbb962b3d49f693bb3b2bc85ffcf 100644 (file)
@@ -587,6 +587,7 @@ fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
             UnsafetyMismatch(x) => UnsafetyMismatch(x),
             AbiMismatch(x) => AbiMismatch(x),
             Mutability => Mutability,
+            ArgumentMutability(i) => ArgumentMutability(i),
             TupleSize(x) => TupleSize(x),
             FixedArraySize(x) => FixedArraySize(x),
             ArgCount => ArgCount,
@@ -607,6 +608,7 @@ fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
             CyclicTy(t) => return tcx.lift(t).map(|t| CyclicTy(t)),
             CyclicConst(ct) => return tcx.lift(ct).map(|ct| CyclicConst(ct)),
             ProjectionMismatched(x) => ProjectionMismatched(x),
+            ArgumentSorts(x, i) => return tcx.lift(x).map(|x| ArgumentSorts(x, i)),
             Sorts(x) => return tcx.lift(x).map(Sorts),
             ExistentialMismatch(x) => return tcx.lift(x).map(ExistentialMismatch),
             ConstMismatch(x) => return tcx.lift(x).map(ConstMismatch),
index 1377bb781d0086089efd4eec3539947b8e69d05d..9321f11f6593380f749d79476205eca86929f173 100644 (file)
@@ -1031,7 +1031,6 @@ fn resolve_item(&mut self, item: &'ast Item) {
             }
 
             ItemKind::Static(ref ty, _, ref expr) | ItemKind::Const(_, ref ty, ref expr) => {
-                debug!("resolve_item ItemKind::Const");
                 self.with_item_rib(HasGenericParams::No, |this| {
                     this.visit_ty(ty);
                     if let Some(expr) = expr {
@@ -1597,6 +1596,7 @@ fn resolve_pattern_inner(
                         .try_resolve_as_non_binding(pat_src, pat, bmode, ident, has_sub)
                         .unwrap_or_else(|| self.fresh_binding(ident, pat.id, pat_src, bindings));
                     self.r.record_partial_res(pat.id, PartialRes::new(res));
+                    self.r.record_pat_span(pat.id, pat.span);
                 }
                 PatKind::TupleStruct(ref path, ref sub_patterns) => {
                     self.smart_resolve_path(
index 3fdd47e1ecb8e627957770f9f2b851ee6059a45a..129954381c9baf497321a6e1aea4350cfef88ce6 100644 (file)
@@ -891,6 +891,10 @@ pub struct Resolver<'a> {
     /// "self-confirming" import resolutions during import validation.
     unusable_binding: Option<&'a NameBinding<'a>>,
 
+    // Spans for local variables found during pattern resolution.
+    // Used for suggestions during error reporting.
+    pat_span_map: NodeMap<Span>,
+
     /// Resolutions for nodes that have a single resolution.
     partial_res_map: NodeMap<PartialRes>,
     /// Resolutions for import nodes, which have multiple resolutions in different namespaces.
@@ -1270,6 +1274,7 @@ pub fn new(
             last_import_segment: false,
             unusable_binding: None,
 
+            pat_span_map: Default::default(),
             partial_res_map: Default::default(),
             import_res_map: Default::default(),
             label_res_map: Default::default(),
@@ -1917,7 +1922,6 @@ fn resolve_ident_in_lexical_scope(
                 return Some(LexicalScopeBinding::Item(binding));
             }
         }
-
         self.early_resolve_ident_in_lexical_scope(
             orig_ident,
             ScopeSet::Late(ns, module, record_used_id),
@@ -2394,7 +2398,59 @@ enum FindBindingResult<'a> {
                             .next()
                             .map_or(false, |c| c.is_ascii_uppercase())
                         {
-                            (format!("use of undeclared type `{}`", ident), None)
+                            // Check whether the name refers to an item in the value namespace.
+                            let suggestion = if ribs.is_some() {
+                                let match_span = match self.resolve_ident_in_lexical_scope(
+                                    ident,
+                                    ValueNS,
+                                    parent_scope,
+                                    None,
+                                    path_span,
+                                    &ribs.unwrap()[ValueNS],
+                                ) {
+                                    // Name matches a local variable. For example:
+                                    // ```
+                                    // fn f() {
+                                    //     let Foo: &str = "";
+                                    //     println!("{}", Foo::Bar); // Name refers to local
+                                    //                               // variable `Foo`.
+                                    // }
+                                    // ```
+                                    Some(LexicalScopeBinding::Res(Res::Local(id))) => {
+                                        Some(*self.pat_span_map.get(&id).unwrap())
+                                    }
+
+                                    // Name matches item from a local name binding
+                                    // created by `use` declaration. For example:
+                                    // ```
+                                    // pub Foo: &str = "";
+                                    //
+                                    // mod submod {
+                                    //     use super::Foo;
+                                    //     println!("{}", Foo::Bar); // Name refers to local
+                                    //                               // binding `Foo`.
+                                    // }
+                                    // ```
+                                    Some(LexicalScopeBinding::Item(name_binding)) => {
+                                        Some(name_binding.span)
+                                    }
+                                    _ => None,
+                                };
+
+                                if let Some(span) = match_span {
+                                    Some((
+                                        vec![(span, String::from(""))],
+                                        format!("`{}` is defined here, but is not a type", ident),
+                                        Applicability::MaybeIncorrect,
+                                    ))
+                                } else {
+                                    None
+                                }
+                            } else {
+                                None
+                            };
+
+                            (format!("use of undeclared type `{}`", ident), suggestion)
                         } else {
                             (format!("use of undeclared crate or module `{}`", ident), None)
                         }
@@ -2805,6 +2861,11 @@ fn record_partial_res(&mut self, node_id: NodeId, resolution: PartialRes) {
         }
     }
 
+    fn record_pat_span(&mut self, node: NodeId, span: Span) {
+        debug!("(recording pat) recording {:?} for {:?}", node, span);
+        self.pat_span_map.insert(node, span);
+    }
+
     fn is_accessible_from(&self, vis: ty::Visibility, module: Module<'a>) -> bool {
         vis.is_accessible_from(module.nearest_parent_mod, self)
     }
index f044daa4509186c676629caa8a9bf20a670da719..60ca562f9920068d44fc8e5635a65b7ed0a4652b 100644 (file)
@@ -278,9 +278,8 @@ fn compare_predicate_entailment<'tcx>(
         if let Err(terr) = sub_result {
             debug!("sub_types failed: impl ty {:?}, trait ty {:?}", impl_fty, trait_fty);
 
-            let (impl_err_span, trait_err_span) = extract_spans_for_error_reporting(
-                &infcx, param_env, &terr, &cause, impl_m, impl_sig, trait_m, trait_sig,
-            );
+            let (impl_err_span, trait_err_span) =
+                extract_spans_for_error_reporting(&infcx, &terr, &cause, impl_m, trait_m);
 
             cause.make_mut().span = impl_err_span;
 
@@ -291,18 +290,79 @@ fn compare_predicate_entailment<'tcx>(
                 "method `{}` has an incompatible type for trait",
                 trait_m.ident
             );
-            if let TypeError::Mutability = terr {
-                if let Some(trait_err_span) = trait_err_span {
-                    if let Ok(trait_err_str) = tcx.sess.source_map().span_to_snippet(trait_err_span)
+            match &terr {
+                TypeError::ArgumentMutability(0) | TypeError::ArgumentSorts(_, 0)
+                    if trait_m.fn_has_self_parameter =>
+                {
+                    let ty = trait_sig.inputs()[0];
+                    let sugg = match ExplicitSelf::determine(ty, |_| ty == impl_trait_ref.self_ty())
                     {
+                        ExplicitSelf::ByValue => "self".to_owned(),
+                        ExplicitSelf::ByReference(_, hir::Mutability::Not) => "&self".to_owned(),
+                        ExplicitSelf::ByReference(_, hir::Mutability::Mut) => {
+                            "&mut self".to_owned()
+                        }
+                        _ => format!("self: {}", ty),
+                    };
+
+                    // When the `impl` receiver is an arbitrary self type, like `self: Box<Self>`, the
+                    // span points only at the type `Box<Self`>, but we want to cover the whole
+                    // argument pattern and type.
+                    let impl_m_hir_id =
+                        tcx.hir().local_def_id_to_hir_id(impl_m.def_id.expect_local());
+                    let span = match tcx.hir().expect_impl_item(impl_m_hir_id).kind {
+                        ImplItemKind::Fn(ref sig, body) => tcx
+                            .hir()
+                            .body_param_names(body)
+                            .zip(sig.decl.inputs.iter())
+                            .map(|(param, ty)| param.span.to(ty.span))
+                            .next()
+                            .unwrap_or(impl_err_span),
+                        _ => bug!("{:?} is not a method", impl_m),
+                    };
+
+                    diag.span_suggestion(
+                        span,
+                        "change the self-receiver type to match the trait",
+                        sugg,
+                        Applicability::MachineApplicable,
+                    );
+                }
+                TypeError::ArgumentMutability(i) | TypeError::ArgumentSorts(_, i) => {
+                    if trait_sig.inputs().len() == *i {
+                        // Suggestion to change output type. We do not suggest in `async` functions
+                        // to avoid complex logic or incorrect output.
+                        let impl_m_hir_id =
+                            tcx.hir().local_def_id_to_hir_id(impl_m.def_id.expect_local());
+                        match tcx.hir().expect_impl_item(impl_m_hir_id).kind {
+                            ImplItemKind::Fn(ref sig, _)
+                                if sig.header.asyncness == hir::IsAsync::NotAsync =>
+                            {
+                                let msg = "change the output type to match the trait";
+                                let ap = Applicability::MachineApplicable;
+                                match sig.decl.output {
+                                    hir::FnRetTy::DefaultReturn(sp) => {
+                                        let sugg = format!("-> {} ", trait_sig.output());
+                                        diag.span_suggestion_verbose(sp, msg, sugg, ap);
+                                    }
+                                    hir::FnRetTy::Return(hir_ty) => {
+                                        let sugg = trait_sig.output().to_string();
+                                        diag.span_suggestion(hir_ty.span, msg, sugg, ap);
+                                    }
+                                };
+                            }
+                            _ => {}
+                        };
+                    } else if let Some(trait_ty) = trait_sig.inputs().get(*i) {
                         diag.span_suggestion(
                             impl_err_span,
-                            "consider changing the mutability to match the trait",
-                            trait_err_str,
+                            "change the parameter type to match the trait",
+                            trait_ty.to_string(),
                             Applicability::MachineApplicable,
                         );
                     }
                 }
+                _ => {}
             }
 
             infcx.note_type_err(
@@ -385,86 +445,35 @@ fn check_region_bounds_on_impl_item<'tcx>(
 
 fn extract_spans_for_error_reporting<'a, 'tcx>(
     infcx: &infer::InferCtxt<'a, 'tcx>,
-    param_env: ty::ParamEnv<'tcx>,
     terr: &TypeError<'_>,
     cause: &ObligationCause<'tcx>,
     impl_m: &ty::AssocItem,
-    impl_sig: ty::FnSig<'tcx>,
     trait_m: &ty::AssocItem,
-    trait_sig: ty::FnSig<'tcx>,
 ) -> (Span, Option<Span>) {
     let tcx = infcx.tcx;
     let impl_m_hir_id = tcx.hir().local_def_id_to_hir_id(impl_m.def_id.expect_local());
-    let (impl_m_output, impl_m_iter) = match tcx.hir().expect_impl_item(impl_m_hir_id).kind {
-        ImplItemKind::Fn(ref impl_m_sig, _) => {
-            (&impl_m_sig.decl.output, impl_m_sig.decl.inputs.iter())
+    let mut impl_args = match tcx.hir().expect_impl_item(impl_m_hir_id).kind {
+        ImplItemKind::Fn(ref sig, _) => {
+            sig.decl.inputs.iter().map(|t| t.span).chain(iter::once(sig.decl.output.span()))
         }
         _ => bug!("{:?} is not a method", impl_m),
     };
-
-    match *terr {
-        TypeError::Mutability => {
-            if let Some(def_id) = trait_m.def_id.as_local() {
-                let trait_m_hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
-                let trait_m_iter = match tcx.hir().expect_trait_item(trait_m_hir_id).kind {
-                    TraitItemKind::Fn(ref trait_m_sig, _) => trait_m_sig.decl.inputs.iter(),
-                    _ => bug!("{:?} is not a TraitItemKind::Fn", trait_m),
-                };
-
-                iter::zip(impl_m_iter, trait_m_iter)
-                    .find(|&(ref impl_arg, ref trait_arg)| {
-                        match (&impl_arg.kind, &trait_arg.kind) {
-                            (
-                                &hir::TyKind::Rptr(_, ref impl_mt),
-                                &hir::TyKind::Rptr(_, ref trait_mt),
-                            )
-                            | (&hir::TyKind::Ptr(ref impl_mt), &hir::TyKind::Ptr(ref trait_mt)) => {
-                                impl_mt.mutbl != trait_mt.mutbl
-                            }
-                            _ => false,
-                        }
-                    })
-                    .map(|(ref impl_arg, ref trait_arg)| (impl_arg.span, Some(trait_arg.span)))
-                    .unwrap_or_else(|| (cause.span(tcx), tcx.hir().span_if_local(trait_m.def_id)))
-            } else {
-                (cause.span(tcx), tcx.hir().span_if_local(trait_m.def_id))
+    let trait_args = trait_m.def_id.as_local().map(|def_id| {
+        let trait_m_hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
+        match tcx.hir().expect_trait_item(trait_m_hir_id).kind {
+            TraitItemKind::Fn(ref sig, _) => {
+                sig.decl.inputs.iter().map(|t| t.span).chain(iter::once(sig.decl.output.span()))
             }
+            _ => bug!("{:?} is not a TraitItemKind::Fn", trait_m),
         }
-        TypeError::Sorts(ExpectedFound { .. }) => {
-            if let Some(def_id) = trait_m.def_id.as_local() {
-                let trait_m_hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
-                let (trait_m_output, trait_m_iter) =
-                    match tcx.hir().expect_trait_item(trait_m_hir_id).kind {
-                        TraitItemKind::Fn(ref trait_m_sig, _) => {
-                            (&trait_m_sig.decl.output, trait_m_sig.decl.inputs.iter())
-                        }
-                        _ => bug!("{:?} is not a TraitItemKind::Fn", trait_m),
-                    };
+    });
 
-                let impl_iter = impl_sig.inputs().iter();
-                let trait_iter = trait_sig.inputs().iter();
-                iter::zip(iter::zip(impl_iter, trait_iter), iter::zip(impl_m_iter, trait_m_iter))
-                    .find_map(|((&impl_arg_ty, &trait_arg_ty), (impl_arg, trait_arg))| match infcx
-                        .at(&cause, param_env)
-                        .sub(trait_arg_ty, impl_arg_ty)
-                    {
-                        Ok(_) => None,
-                        Err(_) => Some((impl_arg.span, Some(trait_arg.span))),
-                    })
-                    .unwrap_or_else(|| {
-                        if infcx
-                            .at(&cause, param_env)
-                            .sup(trait_sig.output(), impl_sig.output())
-                            .is_err()
-                        {
-                            (impl_m_output.span(), Some(trait_m_output.span()))
-                        } else {
-                            (cause.span(tcx), tcx.hir().span_if_local(trait_m.def_id))
-                        }
-                    })
-            } else {
-                (cause.span(tcx), tcx.hir().span_if_local(trait_m.def_id))
-            }
+    match *terr {
+        TypeError::ArgumentMutability(i) => {
+            (impl_args.nth(i).unwrap(), trait_args.and_then(|mut args| args.nth(i)))
+        }
+        TypeError::ArgumentSorts(ExpectedFound { .. }, i) => {
+            (impl_args.nth(i).unwrap(), trait_args.and_then(|mut args| args.nth(i)))
         }
         _ => (cause.span(tcx), tcx.hir().span_if_local(trait_m.def_id)),
     }
@@ -514,8 +523,7 @@ fn compare_self_type<'tcx>(
                 tcx.sess,
                 impl_m_span,
                 E0185,
-                "method `{}` has a `{}` declaration in the impl, but \
-                                            not in the trait",
+                "method `{}` has a `{}` declaration in the impl, but not in the trait",
                 trait_m.ident,
                 self_descr
             );
@@ -535,8 +543,7 @@ fn compare_self_type<'tcx>(
                 tcx.sess,
                 impl_m_span,
                 E0186,
-                "method `{}` has a `{}` declaration in the trait, but \
-                                            not in the impl",
+                "method `{}` has a `{}` declaration in the trait, but not in the impl",
                 trait_m.ident,
                 self_descr
             );
@@ -993,8 +1000,7 @@ fn nested_visit_map(
                 tcx.sess,
                 cause.span,
                 E0326,
-                "implemented const `{}` has an incompatible type for \
-                                             trait",
+                "implemented const `{}` has an incompatible type for trait",
                 trait_c.ident
             );
 
index 8f52985d1df717327a4d149302c436386df300ff..b6ce825e2477a53eed05f3787137e61781d9ebd3 100644 (file)
@@ -12,7 +12,6 @@
 use crate::fmt;
 use crate::hash::{self, Hash};
 use crate::iter::TrustedLen;
-use crate::marker::Unsize;
 use crate::mem::{self, MaybeUninit};
 use crate::ops::{Index, IndexMut};
 use crate::slice::{Iter, IterMut};
     unsafe { &mut *(s as *mut T).cast::<[T; 1]>() }
 }
 
-/// Utility trait implemented only on arrays of fixed size
-///
-/// This trait can be used to implement other traits on fixed-size arrays
-/// without causing much metadata bloat.
-///
-/// The trait is marked unsafe in order to restrict implementors to fixed-size
-/// arrays. A user of this trait can assume that implementors have the exact
-/// layout in memory of a fixed size array (for example, for unsafe
-/// initialization).
-///
-/// Note that the traits [`AsRef`] and [`AsMut`] provide similar methods for types that
-/// may not be fixed-size arrays. Implementors should prefer those traits
-/// instead.
-#[unstable(feature = "fixed_size_array", issue = "27778")]
-pub unsafe trait FixedSizeArray<T> {
-    /// Converts the array to immutable slice
-    #[unstable(feature = "fixed_size_array", issue = "27778")]
-    fn as_slice(&self) -> &[T];
-    /// Converts the array to mutable slice
-    #[unstable(feature = "fixed_size_array", issue = "27778")]
-    fn as_mut_slice(&mut self) -> &mut [T];
-}
-
-#[unstable(feature = "fixed_size_array", issue = "27778")]
-unsafe impl<T, A: Unsize<[T]>> FixedSizeArray<T> for A {
-    #[inline]
-    fn as_slice(&self) -> &[T] {
-        self
-    }
-    #[inline]
-    fn as_mut_slice(&mut self) -> &mut [T] {
-        self
-    }
-}
-
 /// The error type returned when a conversion from a slice to an array fails.
 #[stable(feature = "try_from", since = "1.34.0")]
 #[derive(Debug, Copy, Clone)]
index 89c2a969c28bb34af9ccfd5475a7064f4a36ba94..ce7480ce2ee892317e744af6794574a1e21ebc54 100644 (file)
@@ -1,24 +1,6 @@
-use core::array::{self, FixedSizeArray, IntoIter};
+use core::array::{self, IntoIter};
 use core::convert::TryFrom;
 
-#[test]
-fn fixed_size_array() {
-    let mut array = [0; 64];
-    let mut zero_sized = [(); 64];
-    let mut empty_array = [0; 0];
-    let mut empty_zero_sized = [(); 0];
-
-    assert_eq!(FixedSizeArray::as_slice(&array).len(), 64);
-    assert_eq!(FixedSizeArray::as_slice(&zero_sized).len(), 64);
-    assert_eq!(FixedSizeArray::as_slice(&empty_array).len(), 0);
-    assert_eq!(FixedSizeArray::as_slice(&empty_zero_sized).len(), 0);
-
-    assert_eq!(FixedSizeArray::as_mut_slice(&mut array).len(), 64);
-    assert_eq!(FixedSizeArray::as_mut_slice(&mut zero_sized).len(), 64);
-    assert_eq!(FixedSizeArray::as_mut_slice(&mut empty_array).len(), 0);
-    assert_eq!(FixedSizeArray::as_mut_slice(&mut empty_zero_sized).len(), 0);
-}
-
 #[test]
 fn array_from_ref() {
     let value: String = "Hello World!".into();
index 7dc6e220c08bcb5c4402bdb3ebf4af62cf8903c4..6624fd473539a98fec245735e5bdab4646088d7d 100644 (file)
@@ -28,7 +28,6 @@
 #![feature(duration_zero)]
 #![feature(exact_size_is_empty)]
 #![feature(extern_types)]
-#![feature(fixed_size_array)]
 #![feature(flt2dec)]
 #![feature(fmt_internals)]
 #![feature(hashmap_internals)]
index 22ca7ed09b42a92f852367a6855c66921d97d6f2..84a642289212c2a37c5dbf871557c61ed979679f 100644 (file)
@@ -16,7 +16,7 @@ cfg-if = { version = "0.1.8", features = ['rustc-dep-of-std'] }
 panic_unwind = { path = "../panic_unwind", optional = true }
 panic_abort = { path = "../panic_abort" }
 core = { path = "../core" }
-libc = { version = "0.2.88", default-features = false, features = ['rustc-dep-of-std'] }
+libc = { version = "0.2.93", default-features = false, features = ['rustc-dep-of-std'] }
 compiler_builtins = { version = "0.1.39" }
 profiler_builtins = { path = "../profiler_builtins", optional = true }
 unwind = { path = "../unwind" }
index 860bc130b7d8b7f52c17dc273db2497e5ab15dce..e6120b8ee31c2dc36e13fa2c701d9e2def2133bb 100644 (file)
@@ -265,8 +265,9 @@ fn inner(path: &Path) -> io::Result<Vec<u8>> {
 /// ```no_run
 /// use std::fs;
 /// use std::net::SocketAddr;
+/// use std::error::Error;
 ///
-/// fn main() -> Result<(), Box<dyn std::error::Error + 'static>> {
+/// fn main() -> Result<(), Box<dyn Error>> {
 ///     let foo: SocketAddr = fs::read_to_string("address.txt")?.parse()?;
 ///     Ok(())
 /// }
index 6baf9f2a464b2ed593b84e6000daa6685b0c40a4..91695ced6a962899e9bdd2ec3e88a58201b5e1e5 100644 (file)
     feature(slice_index_methods, coerce_unsized, sgx_platform)
 )]
 #![deny(rustc::existing_doc_keyword)]
-#![cfg_attr(all(test, target_vendor = "fortanix", target_env = "sgx"), feature(fixed_size_array))]
 // std is implemented with unstable features, many of which are internal
 // compiler details that will never be stable
 // NB: the following list is sorted to minimize merge conflicts.
index c9fdaa50534dda942198dedce211efa4e618d9f2..be7bff1a29c2b4d51e45cbc9afc3b4007e8c8f36 100644 (file)
@@ -5,8 +5,8 @@
 use rustc_errors::emitter::{Emitter, EmitterWriter};
 use rustc_errors::json::JsonEmitter;
 use rustc_feature::UnstableFeatures;
-use rustc_hir::def::{Namespace::TypeNS, Res};
-use rustc_hir::def_id::{CrateNum, DefId, DefIndex, LocalDefId, CRATE_DEF_INDEX, LOCAL_CRATE};
+use rustc_hir::def::Res;
+use rustc_hir::def_id::{CrateNum, DefId, DefIndex, LocalDefId, LOCAL_CRATE};
 use rustc_hir::HirId;
 use rustc_hir::{
     intravisit::{self, NestedVisitorMap, Visitor},
@@ -356,55 +356,7 @@ impl<'tcx> DocContext<'tcx> {
     let (krate, resolver, _) = &*parts;
     let resolver = resolver.borrow().clone();
 
-    // Letting the resolver escape at the end of the function leads to inconsistencies between the
-    // crates the TyCtxt sees and the resolver sees (because the resolver could load more crates
-    // after escaping). Hopefully `IntraLinkCrateLoader` gets all the crates we need ...
-    struct IntraLinkCrateLoader {
-        current_mod: DefId,
-        resolver: Rc<RefCell<interface::BoxedResolver>>,
-    }
-    impl ast::visit::Visitor<'_> for IntraLinkCrateLoader {
-        fn visit_attribute(&mut self, attr: &ast::Attribute) {
-            use crate::html::markdown::{markdown_links, MarkdownLink};
-            use crate::passes::collect_intra_doc_links::Disambiguator;
-
-            if let Some(doc) = attr.doc_str() {
-                for MarkdownLink { link, .. } in markdown_links(&doc.as_str()) {
-                    // FIXME: this misses a *lot* of the preprocessing done in collect_intra_doc_links
-                    // I think most of it shouldn't be necessary since we only need the crate prefix?
-                    let path_str = match Disambiguator::from_str(&link) {
-                        Ok(x) => x.map_or(link.as_str(), |(_, p)| p),
-                        Err(_) => continue,
-                    };
-                    self.resolver.borrow_mut().access(|resolver| {
-                        let _ = resolver.resolve_str_path_error(
-                            attr.span,
-                            path_str,
-                            TypeNS,
-                            self.current_mod,
-                        );
-                    });
-                }
-            }
-            ast::visit::walk_attribute(self, attr);
-        }
-
-        fn visit_item(&mut self, item: &ast::Item) {
-            use rustc_ast_lowering::ResolverAstLowering;
-
-            if let ast::ItemKind::Mod(..) = item.kind {
-                let new_mod =
-                    self.resolver.borrow_mut().access(|resolver| resolver.local_def_id(item.id));
-                let old_mod = mem::replace(&mut self.current_mod, new_mod.to_def_id());
-                ast::visit::walk_item(self, item);
-                self.current_mod = old_mod;
-            } else {
-                ast::visit::walk_item(self, item);
-            }
-        }
-    }
-    let crate_id = LocalDefId { local_def_index: CRATE_DEF_INDEX }.to_def_id();
-    let mut loader = IntraLinkCrateLoader { current_mod: crate_id, resolver };
+    let mut loader = crate::passes::collect_intra_doc_links::IntraLinkCrateLoader::new(resolver);
     ast::visit::walk_crate(&mut loader, krate);
 
     loader.resolver
index 4bc7544e33d1e98060d31a80fd28100740e18370..6342110adfe0bf0ca77fd07647f5f5b0e7e7e6cd 100644 (file)
 
 use super::span_of_attrs;
 
+mod early;
+crate use early::IntraLinkCrateLoader;
+
 crate const COLLECT_INTRA_DOC_LINKS: Pass = Pass {
     name: "collect-intra-doc-links",
     run: collect_intra_doc_links,
     description: "resolves intra-doc links",
 };
 
-crate fn collect_intra_doc_links(krate: Crate, cx: &mut DocContext<'_>) -> Crate {
+fn collect_intra_doc_links(krate: Crate, cx: &mut DocContext<'_>) -> Crate {
     LinkCollector {
         cx,
         mod_ids: Vec::new(),
@@ -892,6 +895,117 @@ fn fold_item(&mut self, item: Item) -> Option<Item> {
     }
 }
 
+enum PreprocessingError<'a> {
+    Anchor(AnchorFailure),
+    Disambiguator(Range<usize>, String),
+    Resolution(ResolutionFailure<'a>, String, Option<Disambiguator>),
+}
+
+impl From<AnchorFailure> for PreprocessingError<'_> {
+    fn from(err: AnchorFailure) -> Self {
+        Self::Anchor(err)
+    }
+}
+
+struct PreprocessingInfo {
+    path_str: String,
+    disambiguator: Option<Disambiguator>,
+    extra_fragment: Option<String>,
+    link_text: String,
+}
+
+/// Returns:
+/// - `None` if the link should be ignored.
+/// - `Some(Err)` if the link should emit an error
+/// - `Some(Ok)` if the link is valid
+///
+/// `link_buffer` is needed for lifetime reasons; it will always be overwritten and the contents ignored.
+fn preprocess_link<'a>(
+    ori_link: &'a MarkdownLink,
+) -> Option<Result<PreprocessingInfo, PreprocessingError<'a>>> {
+    // [] is mostly likely not supposed to be a link
+    if ori_link.link.is_empty() {
+        return None;
+    }
+
+    // Bail early for real links.
+    if ori_link.link.contains('/') {
+        return None;
+    }
+
+    let stripped = ori_link.link.replace("`", "");
+    let mut parts = stripped.split('#');
+
+    let link = parts.next().unwrap();
+    if link.trim().is_empty() {
+        // This is an anchor to an element of the current page, nothing to do in here!
+        return None;
+    }
+    let extra_fragment = parts.next();
+    if parts.next().is_some() {
+        // A valid link can't have multiple #'s
+        return Some(Err(AnchorFailure::MultipleAnchors.into()));
+    }
+
+    // Parse and strip the disambiguator from the link, if present.
+    let (path_str, disambiguator) = match Disambiguator::from_str(&link) {
+        Ok(Some((d, path))) => (path.trim(), Some(d)),
+        Ok(None) => (link.trim(), None),
+        Err((err_msg, relative_range)) => {
+            // Only report error if we would not have ignored this link. See issue #83859.
+            if !should_ignore_link_with_disambiguators(link) {
+                let no_backticks_range = range_between_backticks(&ori_link);
+                let disambiguator_range = (no_backticks_range.start + relative_range.start)
+                    ..(no_backticks_range.start + relative_range.end);
+                return Some(Err(PreprocessingError::Disambiguator(disambiguator_range, err_msg)));
+            } else {
+                return None;
+            }
+        }
+    };
+
+    if should_ignore_link(path_str) {
+        return None;
+    }
+
+    // We stripped `()` and `!` when parsing the disambiguator.
+    // Add them back to be displayed, but not prefix disambiguators.
+    let link_text =
+        disambiguator.map(|d| d.display_for(path_str)).unwrap_or_else(|| path_str.to_owned());
+
+    // Strip generics from the path.
+    let path_str = if path_str.contains(['<', '>'].as_slice()) {
+        match strip_generics_from_path(&path_str) {
+            Ok(path) => path,
+            Err(err_kind) => {
+                debug!("link has malformed generics: {}", path_str);
+                return Some(Err(PreprocessingError::Resolution(
+                    err_kind,
+                    path_str.to_owned(),
+                    disambiguator,
+                )));
+            }
+        }
+    } else {
+        path_str.to_owned()
+    };
+
+    // Sanity check to make sure we don't have any angle brackets after stripping generics.
+    assert!(!path_str.contains(['<', '>'].as_slice()));
+
+    // The link is not an intra-doc link if it still contains spaces after stripping generics.
+    if path_str.contains(' ') {
+        return None;
+    }
+
+    Some(Ok(PreprocessingInfo {
+        path_str,
+        disambiguator,
+        extra_fragment: extra_fragment.map(String::from),
+        link_text,
+    }))
+}
+
 impl LinkCollector<'_, '_> {
     /// This is the entry point for resolving an intra-doc link.
     ///
@@ -907,16 +1021,6 @@ fn resolve_link(
     ) -> Option<ItemLink> {
         trace!("considering link '{}'", ori_link.link);
 
-        // Bail early for real links.
-        if ori_link.link.contains('/') {
-            return None;
-        }
-
-        // [] is mostly likely not supposed to be a link
-        if ori_link.link.is_empty() {
-            return None;
-        }
-
         let diag_info = DiagnosticInfo {
             item,
             dox,
@@ -924,47 +1028,29 @@ fn resolve_link(
             link_range: ori_link.range.clone(),
         };
 
-        let link = ori_link.link.replace("`", "");
-        let no_backticks_range = range_between_backticks(&ori_link);
-        let parts = link.split('#').collect::<Vec<_>>();
-        let (link, extra_fragment) = if parts.len() > 2 {
-            // A valid link can't have multiple #'s
-            anchor_failure(self.cx, diag_info, AnchorFailure::MultipleAnchors);
-            return None;
-        } else if parts.len() == 2 {
-            if parts[0].trim().is_empty() {
-                // This is an anchor to an element of the current page, nothing to do in here!
-                return None;
-            }
-            (parts[0], Some(parts[1].to_owned()))
-        } else {
-            (parts[0], None)
-        };
-
-        // Parse and strip the disambiguator from the link, if present.
-        let (mut path_str, disambiguator) = match Disambiguator::from_str(&link) {
-            Ok(Some((d, path))) => (path.trim(), Some(d)),
-            Ok(None) => (link.trim(), None),
-            Err((err_msg, relative_range)) => {
-                if !should_ignore_link_with_disambiguators(link) {
-                    // Only report error if we would not have ignored this link.
-                    // See issue #83859.
-                    let disambiguator_range = (no_backticks_range.start + relative_range.start)
-                        ..(no_backticks_range.start + relative_range.end);
-                    disambiguator_error(self.cx, diag_info, disambiguator_range, &err_msg);
+        let PreprocessingInfo { path_str, disambiguator, extra_fragment, link_text } =
+            match preprocess_link(&ori_link)? {
+                Ok(x) => x,
+                Err(err) => {
+                    match err {
+                        PreprocessingError::Anchor(err) => anchor_failure(self.cx, diag_info, err),
+                        PreprocessingError::Disambiguator(range, msg) => {
+                            disambiguator_error(self.cx, diag_info, range, &msg)
+                        }
+                        PreprocessingError::Resolution(err, path_str, disambiguator) => {
+                            resolution_failure(
+                                self,
+                                diag_info,
+                                &path_str,
+                                disambiguator,
+                                smallvec![err],
+                            );
+                        }
+                    }
+                    return None;
                 }
-                return None;
-            }
-        };
-
-        if should_ignore_link(path_str) {
-            return None;
-        }
-
-        // We stripped `()` and `!` when parsing the disambiguator.
-        // Add them back to be displayed, but not prefix disambiguators.
-        let link_text =
-            disambiguator.map(|d| d.display_for(path_str)).unwrap_or_else(|| path_str.to_owned());
+            };
+        let mut path_str = &*path_str;
 
         // In order to correctly resolve intra-doc links we need to
         // pick a base AST node to work from.  If the documentation for
@@ -1029,39 +1115,12 @@ fn resolve_link(
             module_id = DefId { krate, index: CRATE_DEF_INDEX };
         }
 
-        // Strip generics from the path.
-        let stripped_path_string;
-        if path_str.contains(['<', '>'].as_slice()) {
-            stripped_path_string = match strip_generics_from_path(path_str) {
-                Ok(path) => path,
-                Err(err_kind) => {
-                    debug!("link has malformed generics: {}", path_str);
-                    resolution_failure(
-                        self,
-                        diag_info,
-                        path_str,
-                        disambiguator,
-                        smallvec![err_kind],
-                    );
-                    return None;
-                }
-            };
-            path_str = &stripped_path_string;
-        }
-        // Sanity check to make sure we don't have any angle brackets after stripping generics.
-        assert!(!path_str.contains(['<', '>'].as_slice()));
-
-        // The link is not an intra-doc link if it still contains spaces after stripping generics.
-        if path_str.contains(' ') {
-            return None;
-        }
-
         let (mut res, mut fragment) = self.resolve_with_disambiguator_cached(
             ResolutionInfo {
                 module_id,
                 dis: disambiguator,
                 path_str: path_str.to_owned(),
-                extra_fragment,
+                extra_fragment: extra_fragment.map(String::from),
             },
             diag_info.clone(), // this struct should really be Copy, but Range is not :(
             matches!(ori_link.kind, LinkType::Reference | LinkType::Shortcut),
@@ -1438,7 +1497,7 @@ fn should_ignore_link(path_str: &str) -> bool {
 
 #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
 /// Disambiguators for a link.
-crate enum Disambiguator {
+enum Disambiguator {
     /// `prim@`
     ///
     /// This is buggy, see <https://github.com/rust-lang/rust/pull/77875#discussion_r503583103>
@@ -1467,7 +1526,7 @@ fn display_for(&self, path: &str) -> String {
     /// This returns `Ok(Some(...))` if a disambiguator was found,
     /// `Ok(None)` if no disambiguator was found, or `Err(...)`
     /// if there was a problem with the disambiguator.
-    crate fn from_str(link: &str) -> Result<Option<(Self, &str)>, (String, Range<usize>)> {
+    fn from_str(link: &str) -> Result<Option<(Self, &str)>, (String, Range<usize>)> {
         use Disambiguator::{Kind, Namespace as NS, Primitive};
 
         if let Some(idx) = link.find('@') {
diff --git a/src/librustdoc/passes/collect_intra_doc_links/early.rs b/src/librustdoc/passes/collect_intra_doc_links/early.rs
new file mode 100644 (file)
index 0000000..7cba252
--- /dev/null
@@ -0,0 +1,63 @@
+use rustc_ast as ast;
+use rustc_hir::def::Namespace::TypeNS;
+use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_INDEX};
+use rustc_interface::interface;
+
+use std::cell::RefCell;
+use std::mem;
+use std::rc::Rc;
+
+// Letting the resolver escape at the end of the function leads to inconsistencies between the
+// crates the TyCtxt sees and the resolver sees (because the resolver could load more crates
+// after escaping). Hopefully `IntraLinkCrateLoader` gets all the crates we need ...
+crate struct IntraLinkCrateLoader {
+    current_mod: DefId,
+    crate resolver: Rc<RefCell<interface::BoxedResolver>>,
+}
+
+impl IntraLinkCrateLoader {
+    crate fn new(resolver: Rc<RefCell<interface::BoxedResolver>>) -> Self {
+        let crate_id = LocalDefId { local_def_index: CRATE_DEF_INDEX }.to_def_id();
+        Self { current_mod: crate_id, resolver }
+    }
+}
+
+impl ast::visit::Visitor<'_> for IntraLinkCrateLoader {
+    fn visit_attribute(&mut self, attr: &ast::Attribute) {
+        use crate::html::markdown::markdown_links;
+        use crate::passes::collect_intra_doc_links::preprocess_link;
+
+        if let Some(doc) = attr.doc_str() {
+            for link in markdown_links(&doc.as_str()) {
+                let path_str = if let Some(Ok(x)) = preprocess_link(&link) {
+                    x.path_str
+                } else {
+                    continue;
+                };
+                self.resolver.borrow_mut().access(|resolver| {
+                    let _ = resolver.resolve_str_path_error(
+                        attr.span,
+                        &path_str,
+                        TypeNS,
+                        self.current_mod,
+                    );
+                });
+            }
+        }
+        ast::visit::walk_attribute(self, attr);
+    }
+
+    fn visit_item(&mut self, item: &ast::Item) {
+        use rustc_ast_lowering::ResolverAstLowering;
+
+        if let ast::ItemKind::Mod(..) = item.kind {
+            let new_mod =
+                self.resolver.borrow_mut().access(|resolver| resolver.local_def_id(item.id));
+            let old_mod = mem::replace(&mut self.current_mod, new_mod.to_def_id());
+            ast::visit::walk_item(self, item);
+            self.current_mod = old_mod;
+        } else {
+            ast::visit::walk_item(self, item);
+        }
+    }
+}
diff --git a/src/test/rustdoc-ui/bare-urls.fixed b/src/test/rustdoc-ui/bare-urls.fixed
new file mode 100644 (file)
index 0000000..23aa5c4
--- /dev/null
@@ -0,0 +1,60 @@
+// run-rustfix
+
+#![deny(rustdoc::bare_urls)]
+
+/// <https://somewhere.com>
+//~^ ERROR this URL is not a hyperlink
+/// <https://somewhere.com/a>
+//~^ ERROR this URL is not a hyperlink
+/// <https://www.somewhere.com>
+//~^ ERROR this URL is not a hyperlink
+/// <https://www.somewhere.com/a>
+//~^ ERROR this URL is not a hyperlink
+/// <https://subdomain.example.com>
+//~^ ERROR not a hyperlink
+/// <https://somewhere.com?>
+//~^ ERROR this URL is not a hyperlink
+/// <https://somewhere.com/a?>
+//~^ ERROR this URL is not a hyperlink
+/// <https://somewhere.com?hello=12>
+//~^ ERROR this URL is not a hyperlink
+/// <https://somewhere.com/a?hello=12>
+//~^ ERROR this URL is not a hyperlink
+/// <https://example.com?hello=12#xyz>
+//~^ ERROR this URL is not a hyperlink
+/// <https://example.com/a?hello=12#xyz>
+//~^ ERROR this URL is not a hyperlink
+/// <https://example.com#xyz>
+//~^ ERROR this URL is not a hyperlink
+/// <https://example.com/a#xyz>
+//~^ ERROR this URL is not a hyperlink
+/// <https://somewhere.com?hello=12&bye=11>
+//~^ ERROR this URL is not a hyperlink
+/// <https://somewhere.com/a?hello=12&bye=11>
+//~^ ERROR this URL is not a hyperlink
+/// <https://somewhere.com?hello=12&bye=11#xyz>
+//~^ ERROR this URL is not a hyperlink
+/// hey! <https://somewhere.com/a?hello=12&bye=11#xyz>
+//~^ ERROR this URL is not a hyperlink
+pub fn c() {}
+
+/// <https://somewhere.com>
+/// [a](http://a.com)
+/// [b]
+///
+/// [b]: http://b.com
+///
+/// ```
+/// This link should not be linted: http://example.com
+///
+/// Nor this one: <http://example.com> or this one: [x](http://example.com)
+/// ```
+///
+/// [should_not.lint](should_not.lint)
+pub fn everything_is_fine_here() {}
+
+#[allow(rustdoc::bare_urls)]
+pub mod foo {
+    /// https://somewhere.com/a?hello=12&bye=11#xyz
+    pub fn bar() {}
+}
diff --git a/src/test/rustdoc-ui/bare-urls.rs b/src/test/rustdoc-ui/bare-urls.rs
new file mode 100644 (file)
index 0000000..592f573
--- /dev/null
@@ -0,0 +1,60 @@
+// run-rustfix
+
+#![deny(rustdoc::bare_urls)]
+
+/// https://somewhere.com
+//~^ ERROR this URL is not a hyperlink
+/// https://somewhere.com/a
+//~^ ERROR this URL is not a hyperlink
+/// https://www.somewhere.com
+//~^ ERROR this URL is not a hyperlink
+/// https://www.somewhere.com/a
+//~^ ERROR this URL is not a hyperlink
+/// https://subdomain.example.com
+//~^ ERROR not a hyperlink
+/// https://somewhere.com?
+//~^ ERROR this URL is not a hyperlink
+/// https://somewhere.com/a?
+//~^ ERROR this URL is not a hyperlink
+/// https://somewhere.com?hello=12
+//~^ ERROR this URL is not a hyperlink
+/// https://somewhere.com/a?hello=12
+//~^ ERROR this URL is not a hyperlink
+/// https://example.com?hello=12#xyz
+//~^ ERROR this URL is not a hyperlink
+/// https://example.com/a?hello=12#xyz
+//~^ ERROR this URL is not a hyperlink
+/// https://example.com#xyz
+//~^ ERROR this URL is not a hyperlink
+/// https://example.com/a#xyz
+//~^ ERROR this URL is not a hyperlink
+/// https://somewhere.com?hello=12&bye=11
+//~^ ERROR this URL is not a hyperlink
+/// https://somewhere.com/a?hello=12&bye=11
+//~^ ERROR this URL is not a hyperlink
+/// https://somewhere.com?hello=12&bye=11#xyz
+//~^ ERROR this URL is not a hyperlink
+/// hey! https://somewhere.com/a?hello=12&bye=11#xyz
+//~^ ERROR this URL is not a hyperlink
+pub fn c() {}
+
+/// <https://somewhere.com>
+/// [a](http://a.com)
+/// [b]
+///
+/// [b]: http://b.com
+///
+/// ```
+/// This link should not be linted: http://example.com
+///
+/// Nor this one: <http://example.com> or this one: [x](http://example.com)
+/// ```
+///
+/// [should_not.lint](should_not.lint)
+pub fn everything_is_fine_here() {}
+
+#[allow(rustdoc::bare_urls)]
+pub mod foo {
+    /// https://somewhere.com/a?hello=12&bye=11#xyz
+    pub fn bar() {}
+}
diff --git a/src/test/rustdoc-ui/bare-urls.stderr b/src/test/rustdoc-ui/bare-urls.stderr
new file mode 100644 (file)
index 0000000..6b612f8
--- /dev/null
@@ -0,0 +1,110 @@
+error: this URL is not a hyperlink
+  --> $DIR/bare-urls.rs:5:5
+   |
+LL | /// https://somewhere.com
+   |     ^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<https://somewhere.com>`
+   |
+note: the lint level is defined here
+  --> $DIR/bare-urls.rs:3:9
+   |
+LL | #![deny(rustdoc::bare_urls)]
+   |         ^^^^^^^^^^^^^^^^^^
+
+error: this URL is not a hyperlink
+  --> $DIR/bare-urls.rs:7:5
+   |
+LL | /// https://somewhere.com/a
+   |     ^^^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<https://somewhere.com/a>`
+
+error: this URL is not a hyperlink
+  --> $DIR/bare-urls.rs:9:5
+   |
+LL | /// https://www.somewhere.com
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<https://www.somewhere.com>`
+
+error: this URL is not a hyperlink
+  --> $DIR/bare-urls.rs:11:5
+   |
+LL | /// https://www.somewhere.com/a
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<https://www.somewhere.com/a>`
+
+error: this URL is not a hyperlink
+  --> $DIR/bare-urls.rs:13:5
+   |
+LL | /// https://subdomain.example.com
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<https://subdomain.example.com>`
+
+error: this URL is not a hyperlink
+  --> $DIR/bare-urls.rs:15:5
+   |
+LL | /// https://somewhere.com?
+   |     ^^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<https://somewhere.com?>`
+
+error: this URL is not a hyperlink
+  --> $DIR/bare-urls.rs:17:5
+   |
+LL | /// https://somewhere.com/a?
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<https://somewhere.com/a?>`
+
+error: this URL is not a hyperlink
+  --> $DIR/bare-urls.rs:19:5
+   |
+LL | /// https://somewhere.com?hello=12
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<https://somewhere.com?hello=12>`
+
+error: this URL is not a hyperlink
+  --> $DIR/bare-urls.rs:21:5
+   |
+LL | /// https://somewhere.com/a?hello=12
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<https://somewhere.com/a?hello=12>`
+
+error: this URL is not a hyperlink
+  --> $DIR/bare-urls.rs:23:5
+   |
+LL | /// https://example.com?hello=12#xyz
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<https://example.com?hello=12#xyz>`
+
+error: this URL is not a hyperlink
+  --> $DIR/bare-urls.rs:25:5
+   |
+LL | /// https://example.com/a?hello=12#xyz
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<https://example.com/a?hello=12#xyz>`
+
+error: this URL is not a hyperlink
+  --> $DIR/bare-urls.rs:27:5
+   |
+LL | /// https://example.com#xyz
+   |     ^^^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<https://example.com#xyz>`
+
+error: this URL is not a hyperlink
+  --> $DIR/bare-urls.rs:29:5
+   |
+LL | /// https://example.com/a#xyz
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<https://example.com/a#xyz>`
+
+error: this URL is not a hyperlink
+  --> $DIR/bare-urls.rs:31:5
+   |
+LL | /// https://somewhere.com?hello=12&bye=11
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<https://somewhere.com?hello=12&bye=11>`
+
+error: this URL is not a hyperlink
+  --> $DIR/bare-urls.rs:33:5
+   |
+LL | /// https://somewhere.com/a?hello=12&bye=11
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<https://somewhere.com/a?hello=12&bye=11>`
+
+error: this URL is not a hyperlink
+  --> $DIR/bare-urls.rs:35:5
+   |
+LL | /// https://somewhere.com?hello=12&bye=11#xyz
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<https://somewhere.com?hello=12&bye=11#xyz>`
+
+error: this URL is not a hyperlink
+  --> $DIR/bare-urls.rs:37:10
+   |
+LL | /// hey! https://somewhere.com/a?hello=12&bye=11#xyz
+   |          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<https://somewhere.com/a?hello=12&bye=11#xyz>`
+
+error: aborting due to 17 previous errors
+
diff --git a/src/test/rustdoc-ui/url-improvements.rs b/src/test/rustdoc-ui/url-improvements.rs
deleted file mode 100644 (file)
index 43a13b0..0000000
+++ /dev/null
@@ -1,58 +0,0 @@
-#![deny(rustdoc::bare_urls)]
-
-/// https://somewhere.com
-//~^ ERROR this URL is not a hyperlink
-/// https://somewhere.com/a
-//~^ ERROR this URL is not a hyperlink
-/// https://www.somewhere.com
-//~^ ERROR this URL is not a hyperlink
-/// https://www.somewhere.com/a
-//~^ ERROR this URL is not a hyperlink
-/// https://subdomain.example.com
-//~^ ERROR not a hyperlink
-/// https://somewhere.com?
-//~^ ERROR this URL is not a hyperlink
-/// https://somewhere.com/a?
-//~^ ERROR this URL is not a hyperlink
-/// https://somewhere.com?hello=12
-//~^ ERROR this URL is not a hyperlink
-/// https://somewhere.com/a?hello=12
-//~^ ERROR this URL is not a hyperlink
-/// https://example.com?hello=12#xyz
-//~^ ERROR this URL is not a hyperlink
-/// https://example.com/a?hello=12#xyz
-//~^ ERROR this URL is not a hyperlink
-/// https://example.com#xyz
-//~^ ERROR this URL is not a hyperlink
-/// https://example.com/a#xyz
-//~^ ERROR this URL is not a hyperlink
-/// https://somewhere.com?hello=12&bye=11
-//~^ ERROR this URL is not a hyperlink
-/// https://somewhere.com/a?hello=12&bye=11
-//~^ ERROR this URL is not a hyperlink
-/// https://somewhere.com?hello=12&bye=11#xyz
-//~^ ERROR this URL is not a hyperlink
-/// hey! https://somewhere.com/a?hello=12&bye=11#xyz
-//~^ ERROR this URL is not a hyperlink
-pub fn c() {}
-
-/// <https://somewhere.com>
-/// [a](http://a.com)
-/// [b]
-///
-/// [b]: http://b.com
-///
-/// ```
-/// This link should not be linted: http://example.com
-///
-/// Nor this one: <http://example.com> or this one: [x](http://example.com)
-/// ```
-///
-/// [should_not.lint](should_not.lint)
-pub fn everything_is_fine_here() {}
-
-#[allow(rustdoc::bare_urls)]
-pub mod foo {
-    /// https://somewhere.com/a?hello=12&bye=11#xyz
-    pub fn bar() {}
-}
diff --git a/src/test/rustdoc-ui/url-improvements.stderr b/src/test/rustdoc-ui/url-improvements.stderr
deleted file mode 100644 (file)
index 3d5ebd8..0000000
+++ /dev/null
@@ -1,110 +0,0 @@
-error: this URL is not a hyperlink
-  --> $DIR/url-improvements.rs:3:5
-   |
-LL | /// https://somewhere.com
-   |     ^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<https://somewhere.com>`
-   |
-note: the lint level is defined here
-  --> $DIR/url-improvements.rs:1:9
-   |
-LL | #![deny(rustdoc::bare_urls)]
-   |         ^^^^^^^^^^^^^^^^^^
-
-error: this URL is not a hyperlink
-  --> $DIR/url-improvements.rs:5:5
-   |
-LL | /// https://somewhere.com/a
-   |     ^^^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<https://somewhere.com/a>`
-
-error: this URL is not a hyperlink
-  --> $DIR/url-improvements.rs:7:5
-   |
-LL | /// https://www.somewhere.com
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<https://www.somewhere.com>`
-
-error: this URL is not a hyperlink
-  --> $DIR/url-improvements.rs:9:5
-   |
-LL | /// https://www.somewhere.com/a
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<https://www.somewhere.com/a>`
-
-error: this URL is not a hyperlink
-  --> $DIR/url-improvements.rs:11:5
-   |
-LL | /// https://subdomain.example.com
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<https://subdomain.example.com>`
-
-error: this URL is not a hyperlink
-  --> $DIR/url-improvements.rs:13:5
-   |
-LL | /// https://somewhere.com?
-   |     ^^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<https://somewhere.com?>`
-
-error: this URL is not a hyperlink
-  --> $DIR/url-improvements.rs:15:5
-   |
-LL | /// https://somewhere.com/a?
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<https://somewhere.com/a?>`
-
-error: this URL is not a hyperlink
-  --> $DIR/url-improvements.rs:17:5
-   |
-LL | /// https://somewhere.com?hello=12
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<https://somewhere.com?hello=12>`
-
-error: this URL is not a hyperlink
-  --> $DIR/url-improvements.rs:19:5
-   |
-LL | /// https://somewhere.com/a?hello=12
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<https://somewhere.com/a?hello=12>`
-
-error: this URL is not a hyperlink
-  --> $DIR/url-improvements.rs:21:5
-   |
-LL | /// https://example.com?hello=12#xyz
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<https://example.com?hello=12#xyz>`
-
-error: this URL is not a hyperlink
-  --> $DIR/url-improvements.rs:23:5
-   |
-LL | /// https://example.com/a?hello=12#xyz
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<https://example.com/a?hello=12#xyz>`
-
-error: this URL is not a hyperlink
-  --> $DIR/url-improvements.rs:25:5
-   |
-LL | /// https://example.com#xyz
-   |     ^^^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<https://example.com#xyz>`
-
-error: this URL is not a hyperlink
-  --> $DIR/url-improvements.rs:27:5
-   |
-LL | /// https://example.com/a#xyz
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<https://example.com/a#xyz>`
-
-error: this URL is not a hyperlink
-  --> $DIR/url-improvements.rs:29:5
-   |
-LL | /// https://somewhere.com?hello=12&bye=11
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<https://somewhere.com?hello=12&bye=11>`
-
-error: this URL is not a hyperlink
-  --> $DIR/url-improvements.rs:31:5
-   |
-LL | /// https://somewhere.com/a?hello=12&bye=11
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<https://somewhere.com/a?hello=12&bye=11>`
-
-error: this URL is not a hyperlink
-  --> $DIR/url-improvements.rs:33:5
-   |
-LL | /// https://somewhere.com?hello=12&bye=11#xyz
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<https://somewhere.com?hello=12&bye=11#xyz>`
-
-error: this URL is not a hyperlink
-  --> $DIR/url-improvements.rs:35:10
-   |
-LL | /// hey! https://somewhere.com/a?hello=12&bye=11#xyz
-   |          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<https://somewhere.com/a?hello=12&bye=11#xyz>`
-
-error: aborting due to 17 previous errors
-
diff --git a/src/test/rustdoc/intra-doc/auxiliary/empty.rs b/src/test/rustdoc/intra-doc/auxiliary/empty.rs
new file mode 100644 (file)
index 0000000..d11c69f
--- /dev/null
@@ -0,0 +1 @@
+// intentionally empty
diff --git a/src/test/rustdoc/intra-doc/auxiliary/empty2.rs b/src/test/rustdoc/intra-doc/auxiliary/empty2.rs
new file mode 100644 (file)
index 0000000..d11c69f
--- /dev/null
@@ -0,0 +1 @@
+// intentionally empty
index 0964c79de068f4ff26edaef5ef241ca249be5725..5d8dcf8bc1d1682357b5cb982c07713c82f6c3f5 100644 (file)
@@ -1,8 +1,19 @@
+// This test is just a little cursed.
 // aux-build:issue-66159-1.rs
 // aux-crate:priv:issue_66159_1=issue-66159-1.rs
+// aux-build:empty.rs
+// aux-crate:priv:empty=empty.rs
+// aux-build:empty2.rs
+// aux-crate:priv:empty2=empty2.rs
 // build-aux-docs
-// compile-flags:-Z unstable-options
+// compile-flags:-Z unstable-options --edition 2018
 
 // @has extern_crate_only_used_in_link/index.html
 // @has - '//a[@href="../issue_66159_1/struct.Something.html"]' 'issue_66159_1::Something'
 //! [issue_66159_1::Something]
+
+// @has - '//a[@href="../empty/index.html"]' 'empty'
+//! [`empty`]
+
+// @has - '//a[@href="../empty2/index.html"]' 'empty2'
+//! [empty2<x>]
index 920f8322813fee7cebbbaf1557197ebdb172330b..3c7dc1fc3c9b23f88e97439f934418204b48713c 100644 (file)
@@ -15,7 +15,10 @@ LL |     fn make() -> Self::Ty {
    |                  -------- type in trait
 ...
 LL |     fn make() -> u8 { 0 }
-   |                  ^^ expected associated type, found `u8`
+   |                  ^^
+   |                  |
+   |                  expected associated type, found `u8`
+   |                  help: change the output type to match the trait: `<A<T> as Tr>::Ty`
    |
    = note: expected fn pointer `fn() -> <A<T> as Tr>::Ty`
               found fn pointer `fn() -> u8`
@@ -30,7 +33,10 @@ LL |     default type Ty = bool;
    |     ----------------------- expected this associated type
 LL | 
 LL |     fn make() -> bool { true }
-   |                  ^^^^ expected associated type, found `bool`
+   |                  ^^^^
+   |                  |
+   |                  expected associated type, found `bool`
+   |                  help: change the output type to match the trait: `<B<T> as Tr>::Ty`
    |
    = note: expected fn pointer `fn() -> <B<T> as Tr>::Ty`
               found fn pointer `fn() -> bool`
diff --git a/src/test/ui/compare-method/bad-self-type.rs b/src/test/ui/compare-method/bad-self-type.rs
new file mode 100644 (file)
index 0000000..f42a9e4
--- /dev/null
@@ -0,0 +1,26 @@
+use std::future::Future;
+use std::task::{Context, Poll};
+
+fn main() {}
+
+struct MyFuture {}
+
+impl Future for MyFuture {
+    type Output = ();
+    fn poll(self, _: &mut Context<'_>) -> Poll<()> {
+    //~^ ERROR method `poll` has an incompatible type for trait
+        todo!()
+    }
+}
+
+trait T {
+    fn foo(self);
+    fn bar(self) -> Option<()>;
+}
+
+impl T for MyFuture {
+    fn foo(self: Box<Self>) {}
+    //~^ ERROR method `foo` has an incompatible type for trait
+    fn bar(self) {}
+    //~^ ERROR method `bar` has an incompatible type for trait
+}
diff --git a/src/test/ui/compare-method/bad-self-type.stderr b/src/test/ui/compare-method/bad-self-type.stderr
new file mode 100644 (file)
index 0000000..76f91fb
--- /dev/null
@@ -0,0 +1,46 @@
+error[E0053]: method `poll` has an incompatible type for trait
+  --> $DIR/bad-self-type.rs:10:13
+   |
+LL |     fn poll(self, _: &mut Context<'_>) -> Poll<()> {
+   |             ^^^^
+   |             |
+   |             expected struct `Pin`, found struct `MyFuture`
+   |             help: change the self-receiver type to match the trait: `self: Pin<&mut MyFuture>`
+   |
+   = note: expected fn pointer `fn(Pin<&mut MyFuture>, &mut Context<'_>) -> Poll<_>`
+              found fn pointer `fn(MyFuture, &mut Context<'_>) -> Poll<_>`
+
+error[E0053]: method `foo` has an incompatible type for trait
+  --> $DIR/bad-self-type.rs:22:18
+   |
+LL |     fn foo(self);
+   |            ---- type in trait
+...
+LL |     fn foo(self: Box<Self>) {}
+   |            ------^^^^^^^^^
+   |            |     |
+   |            |     expected struct `MyFuture`, found struct `Box`
+   |            help: change the self-receiver type to match the trait: `self`
+   |
+   = note: expected fn pointer `fn(MyFuture)`
+              found fn pointer `fn(Box<MyFuture>)`
+
+error[E0053]: method `bar` has an incompatible type for trait
+  --> $DIR/bad-self-type.rs:24:18
+   |
+LL |     fn bar(self) -> Option<()>;
+   |                     ---------- type in trait
+...
+LL |     fn bar(self) {}
+   |                  ^ expected enum `Option`, found `()`
+   |
+   = note: expected fn pointer `fn(MyFuture) -> Option<()>`
+              found fn pointer `fn(MyFuture)`
+help: change the output type to match the trait
+   |
+LL |     fn bar(self) -> Option<()> {}
+   |                  ^^^^^^^^^^^^^
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0053`.
index f1f8a663f21209f45f803517c1560da72861238c..d581628ea48adaffbef65f307f500bbb3190350a 100644 (file)
@@ -5,8 +5,10 @@ LL |   fn b<C:Clone,D>(&self, x: C) -> C;
    |                             - type in trait
 ...
 LL |   fn b<F:Clone,G>(&self, _x: G) -> G { panic!() }
-   |        -       -             ^ expected type parameter `F`, found type parameter `G`
-   |        |       |
+   |        -       -             ^
+   |        |       |             |
+   |        |       |             expected type parameter `F`, found type parameter `G`
+   |        |       |             help: change the parameter type to match the trait: `F`
    |        |       found type parameter
    |        expected type parameter
    |
index 638a0093fb21d1df5a86e4b97b741786517c2873..d37670db08537447ae3edf31558ec295efe4560a 100644 (file)
@@ -5,8 +5,10 @@ LL |     fn foo<A: Debug>(&self, a: &A, b: &impl Debug);
    |                                -- type in trait
 ...
 LL |     fn foo<B: Debug>(&self, a: &impl Debug, b: &B) { }
-   |            -                   ^^^^^^^^^^^ expected type parameter `B`, found type parameter `impl Debug`
-   |            |
+   |            -                   ^^^^^^^^^^^
+   |            |                   |
+   |            |                   expected type parameter `B`, found type parameter `impl Debug`
+   |            |                   help: change the parameter type to match the trait: `&B`
    |            expected type parameter
    |
    = note: expected fn pointer `fn(&(), &B, &impl Debug)`
index 961bb7351181e9e2eecb413131668d0c299bdae8..bea24339837a2414cb7ecf02ac6648b287b3a871 100644 (file)
@@ -1,8 +1,11 @@
 error[E0053]: method `fmt` has an incompatible type for trait
-  --> $DIR/trait_type.rs:7:4
+  --> $DIR/trait_type.rs:7:21
    |
 LL |    fn fmt(&self, x: &str) -> () { }
-   |    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ types differ in mutability
+   |                     ^^^^
+   |                     |
+   |                     types differ in mutability
+   |                     help: change the parameter type to match the trait: `&mut Formatter<'_>`
    |
    = note: expected fn pointer `fn(&MyType, &mut Formatter<'_>) -> Result<(), std::fmt::Error>`
               found fn pointer `fn(&MyType, &str)`
index 57447fa48aacc596a83a01dcd316f124cd031d88..6c3651ff1217a28381698ec173b811ac0a11aa52 100644 (file)
@@ -8,7 +8,7 @@ LL |     fn bar(&mut self, other: &dyn Foo) {}
    |                              ^^^^^^^^
    |                              |
    |                              types differ in mutability
-   |                              help: consider changing the mutability to match the trait: `&mut dyn Foo`
+   |                              help: change the parameter type to match the trait: `&mut dyn Foo`
    |
    = note: expected fn pointer `fn(&mut Baz, &mut dyn Foo)`
               found fn pointer `fn(&mut Baz, &dyn Foo)`
index 3bcc50ded84256c3aab89ed97229ecb66b51e59b..6f4813ca6235b1cfb1d8a3331d530d1ff06d42f8 100644 (file)
@@ -1,33 +1,42 @@
 error[E0053]: method `call` has an incompatible type for trait
-  --> $DIR/issue-20225.rs:6:3
+  --> $DIR/issue-20225.rs:6:43
    |
 LL | impl<'a, T> Fn<(&'a T,)> for Foo {
    |          - this type parameter
 LL |   extern "rust-call" fn call(&self, (_,): (T,)) {}
-   |   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `&T`, found type parameter `T`
+   |                                           ^^^^
+   |                                           |
+   |                                           expected `&T`, found type parameter `T`
+   |                                           help: change the parameter type to match the trait: `(&'a T,)`
    |
    = note: expected fn pointer `extern "rust-call" fn(&Foo, (&'a T,))`
               found fn pointer `extern "rust-call" fn(&Foo, (T,))`
 
 error[E0053]: method `call_mut` has an incompatible type for trait
-  --> $DIR/issue-20225.rs:11:3
+  --> $DIR/issue-20225.rs:11:51
    |
 LL | impl<'a, T> FnMut<(&'a T,)> for Foo {
    |          - this type parameter
 LL |   extern "rust-call" fn call_mut(&mut self, (_,): (T,)) {}
-   |   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `&T`, found type parameter `T`
+   |                                                   ^^^^
+   |                                                   |
+   |                                                   expected `&T`, found type parameter `T`
+   |                                                   help: change the parameter type to match the trait: `(&'a T,)`
    |
    = note: expected fn pointer `extern "rust-call" fn(&mut Foo, (&'a T,))`
               found fn pointer `extern "rust-call" fn(&mut Foo, (T,))`
 
 error[E0053]: method `call_once` has an incompatible type for trait
-  --> $DIR/issue-20225.rs:18:3
+  --> $DIR/issue-20225.rs:18:47
    |
 LL | impl<'a, T> FnOnce<(&'a T,)> for Foo {
    |          - this type parameter
 ...
 LL |   extern "rust-call" fn call_once(self, (_,): (T,)) {}
-   |   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `&T`, found type parameter `T`
+   |                                               ^^^^
+   |                                               |
+   |                                               expected `&T`, found type parameter `T`
+   |                                               help: change the parameter type to match the trait: `(&'a T,)`
    |
    = note: expected fn pointer `extern "rust-call" fn(Foo, (&'a T,))`
               found fn pointer `extern "rust-call" fn(Foo, (T,))`
index 35863fbebe3157390d8f30376fcc2b04b4a6f672..d92966da17c4ceb7e2db6a3fb02c81a502cf3560 100644 (file)
@@ -1,8 +1,11 @@
 error[E0053]: method `next` has an incompatible type for trait
-  --> $DIR/issue-21332.rs:5:5
+  --> $DIR/issue-21332.rs:5:27
    |
 LL |     fn next(&mut self) -> Result<i32, i32> { Ok(7) }
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected enum `Option`, found enum `Result`
+   |                           ^^^^^^^^^^^^^^^^
+   |                           |
+   |                           expected enum `Option`, found enum `Result`
+   |                           help: change the output type to match the trait: `Option<i32>`
    |
    = note: expected fn pointer `fn(&mut S) -> Option<i32>`
               found fn pointer `fn(&mut S) -> Result<i32, i32>`
index f80561bf6be80f49a85e489d07ca7c607da8bc4e..71b2a9df09553d49538f881b6c13c3d346223f2b 100644 (file)
@@ -5,7 +5,10 @@ LL |     fn foo(_: fn(u8) -> ());
    |               ------------ type in trait
 ...
 LL |     fn foo(_: fn(u16) -> ()) {}
-   |               ^^^^^^^^^^^^^ expected `u8`, found `u16`
+   |               ^^^^^^^^^^^^^
+   |               |
+   |               expected `u8`, found `u16`
+   |               help: change the parameter type to match the trait: `fn(u8)`
    |
    = note: expected fn pointer `fn(fn(u8))`
               found fn pointer `fn(fn(u16))`
@@ -17,7 +20,10 @@ LL |     fn bar(_: Option<u8>);
    |               ---------- type in trait
 ...
 LL |     fn bar(_: Option<u16>) {}
-   |               ^^^^^^^^^^^ expected `u8`, found `u16`
+   |               ^^^^^^^^^^^
+   |               |
+   |               expected `u8`, found `u16`
+   |               help: change the parameter type to match the trait: `Option<u8>`
    |
    = note: expected fn pointer `fn(Option<u8>)`
               found fn pointer `fn(Option<u16>)`
@@ -29,7 +35,10 @@ LL |     fn baz(_: (u8, u16));
    |               --------- type in trait
 ...
 LL |     fn baz(_: (u16, u16)) {}
-   |               ^^^^^^^^^^ expected `u8`, found `u16`
+   |               ^^^^^^^^^^
+   |               |
+   |               expected `u8`, found `u16`
+   |               help: change the parameter type to match the trait: `(u8, u16)`
    |
    = note: expected fn pointer `fn((u8, _))`
               found fn pointer `fn((u16, _))`
@@ -41,7 +50,10 @@ LL |     fn qux() -> u8;
    |                 -- type in trait
 ...
 LL |     fn qux() -> u16 { 5u16 }
-   |                 ^^^ expected `u8`, found `u16`
+   |                 ^^^
+   |                 |
+   |                 expected `u8`, found `u16`
+   |                 help: change the output type to match the trait: `u8`
    |
    = note: expected fn pointer `fn() -> u8`
               found fn pointer `fn() -> u16`
index e0a3ce922b97023ad510616c7a68abb3031189a0..6ce8126b9f970d64d592d3bf8a2b5c5e7754d11c 100644 (file)
@@ -5,7 +5,10 @@ LL |     fn foo(x: u16);
    |               --- type in trait
 ...
 LL |     fn foo(x: i16) { }
-   |               ^^^ expected `u16`, found `i16`
+   |               ^^^
+   |               |
+   |               expected `u16`, found `i16`
+   |               help: change the parameter type to match the trait: `u16`
    |
    = note: expected fn pointer `fn(u16)`
               found fn pointer `fn(i16)`
@@ -20,7 +23,7 @@ LL |     fn bar(&mut self) { }
    |            ^^^^^^^^^
    |            |
    |            types differ in mutability
-   |            help: consider changing the mutability to match the trait: `&self`
+   |            help: change the self-receiver type to match the trait: `self: &Bar`
    |
    = note: expected fn pointer `fn(&Bar)`
               found fn pointer `fn(&mut Bar)`
index 161843473b6c10f02286d5f6eae9c577a0ec3dd2..2ac4d1c33a9b945c2891d266394963180614a88b 100644 (file)
@@ -5,7 +5,10 @@ LL |     fn foo(x: u16);
    |               --- type in trait
 ...
 LL |     fn foo(x: i16) { }
-   |               ^^^ expected `u16`, found `i16`
+   |               ^^^
+   |               |
+   |               expected `u16`, found `i16`
+   |               help: change the parameter type to match the trait: `u16`
    |
    = note: expected fn pointer `fn(u16)`
               found fn pointer `fn(i16)`
@@ -20,7 +23,7 @@ LL |     fn bar(&mut self, bar: &Bar) { }
    |                            ^^^^
    |                            |
    |                            types differ in mutability
-   |                            help: consider changing the mutability to match the trait: `&mut Bar`
+   |                            help: change the parameter type to match the trait: `&mut Bar`
    |
    = note: expected fn pointer `fn(&mut Bar, &mut Bar)`
               found fn pointer `fn(&mut Bar, &Bar)`
diff --git a/src/test/ui/resolve/issue-81508.rs b/src/test/ui/resolve/issue-81508.rs
new file mode 100644 (file)
index 0000000..23605cd
--- /dev/null
@@ -0,0 +1,22 @@
+// Confusing diagnostic when using variable as a type:
+//
+// Previous warnings indicate Foo is not used, when in fact it is
+// used improperly as a variable or constant. New warning points
+// out user may be trying to use variable as a type. Test demonstrates
+// cases for both local variable and const.
+
+fn main() {
+    let Baz: &str = "";
+
+    println!("{}", Baz::Bar); //~ ERROR: failed to resolve: use of undeclared type `Baz`
+}
+
+#[allow(non_upper_case_globals)]
+pub const Foo: &str = "";
+
+mod submod {
+    use super::Foo;
+    fn function() {
+        println!("{}", Foo::Bar); //~ ERROR: failed to resolve: use of undeclared type `Foo`
+    }
+}
diff --git a/src/test/ui/resolve/issue-81508.stderr b/src/test/ui/resolve/issue-81508.stderr
new file mode 100644 (file)
index 0000000..1555563
--- /dev/null
@@ -0,0 +1,21 @@
+error[E0433]: failed to resolve: use of undeclared type `Baz`
+  --> $DIR/issue-81508.rs:11:20
+   |
+LL |     let Baz: &str = "";
+   |         --- help: `Baz` is defined here, but is not a type
+LL | 
+LL |     println!("{}", Baz::Bar);
+   |                    ^^^ use of undeclared type `Baz`
+
+error[E0433]: failed to resolve: use of undeclared type `Foo`
+  --> $DIR/issue-81508.rs:20:24
+   |
+LL |     use super::Foo;
+   |         ---------- help: `Foo` is defined here, but is not a type
+LL |     fn function() {
+LL |         println!("{}", Foo::Bar);
+   |                        ^^^ use of undeclared type `Foo`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0433`.
index 4c367fb9e9caf4460b87414c0d2c2e79b15c87a3..9f8896f01ee06f90e776c07c1ccbfdfa8a496216 100644 (file)
@@ -1,26 +1,35 @@
 error[E0053]: method `mul` has an incompatible type for trait
-  --> $DIR/wrong-mul-method-signature.rs:16:5
+  --> $DIR/wrong-mul-method-signature.rs:16:21
    |
 LL |     fn mul(self, s: &f64) -> Vec1 {
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `f64`, found `&f64`
+   |                     ^^^^
+   |                     |
+   |                     expected `f64`, found `&f64`
+   |                     help: change the parameter type to match the trait: `f64`
    |
    = note: expected fn pointer `fn(Vec1, f64) -> Vec1`
               found fn pointer `fn(Vec1, &f64) -> Vec1`
 
 error[E0053]: method `mul` has an incompatible type for trait
-  --> $DIR/wrong-mul-method-signature.rs:33:5
+  --> $DIR/wrong-mul-method-signature.rs:33:21
    |
 LL |     fn mul(self, s: f64) -> Vec2 {
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected struct `Vec2`, found `f64`
+   |                     ^^^
+   |                     |
+   |                     expected struct `Vec2`, found `f64`
+   |                     help: change the parameter type to match the trait: `Vec2`
    |
    = note: expected fn pointer `fn(Vec2, Vec2) -> f64`
               found fn pointer `fn(Vec2, f64) -> Vec2`
 
 error[E0053]: method `mul` has an incompatible type for trait
-  --> $DIR/wrong-mul-method-signature.rs:52:5
+  --> $DIR/wrong-mul-method-signature.rs:52:29
    |
 LL |     fn mul(self, s: f64) -> f64 {
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `i32`, found `f64`
+   |                             ^^^
+   |                             |
+   |                             expected `i32`, found `f64`
+   |                             help: change the output type to match the trait: `i32`
    |
    = note: expected fn pointer `fn(Vec3, _) -> i32`
               found fn pointer `fn(Vec3, _) -> f64`