diff --git a/compiler/rustc_borrowck/src/renumber.rs b/compiler/rustc_borrowck/src/renumber.rs index d83d6ade2032c..e355d2b415b03 100644 --- a/compiler/rustc_borrowck/src/renumber.rs +++ b/compiler/rustc_borrowck/src/renumber.rs @@ -34,7 +34,6 @@ pub(crate) enum RegionCtxt { Location(Location), TyContext(TyContext), Free(Symbol), - Bound(Symbol), LateBound(Symbol), Existential(Option), Placeholder(Symbol), diff --git a/compiler/rustc_borrowck/src/universal_regions.rs b/compiler/rustc_borrowck/src/universal_regions.rs index 3dc4569c57b9a..26af86c0cdd49 100644 --- a/compiler/rustc_borrowck/src/universal_regions.rs +++ b/compiler/rustc_borrowck/src/universal_regions.rs @@ -467,15 +467,13 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> { self.infcx.tcx.local_parent(self.mir_def), |r| { debug!(?r); - if !indices.indices.contains_key(&r) { - let region_vid = { - let name = r.get_name_or_anon(); - self.infcx.next_nll_region_var(FR, || RegionCtxt::LateBound(name)) - }; - - debug!(?region_vid); - indices.insert_late_bound_region(r, region_vid.as_var()); - } + let region_vid = { + let name = r.get_name_or_anon(); + self.infcx.next_nll_region_var(FR, || RegionCtxt::LateBound(name)) + }; + + debug!(?region_vid); + indices.insert_late_bound_region(r, region_vid.as_var()); }, ); @@ -484,21 +482,17 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> { self.infcx.num_region_vars() }; - // "Liberate" the late-bound regions. These correspond to - // "local" free regions. + // Converse of above, if this is a function/closure then the late-bound regions declared + // on its signature are local. + // + // We manually loop over `bound_inputs_and_output` instead of using + // `for_each_late_bound_region_in_item` as we may need to add the otherwise + // implicit `ClosureEnv` region. let bound_inputs_and_output = self.compute_inputs_and_output(&indices, defining_ty); - - let inputs_and_output = self.infcx.replace_bound_regions_with_nll_infer_vars( - FR, - self.mir_def, - bound_inputs_and_output, - &mut indices, - ); - // Converse of above, if this is a function/closure then the late-bound regions declared on its - // signature are local. - for_each_late_bound_region_in_item(self.infcx.tcx, self.mir_def, |r| { - debug!(?r); - if !indices.indices.contains_key(&r) { + for (idx, bound_var) in bound_inputs_and_output.bound_vars().iter().enumerate() { + if let ty::BoundVariableKind::Region(kind) = bound_var { + let kind = ty::LateParamRegionKind::from_bound(ty::BoundVar::from_usize(idx), kind); + let r = ty::Region::new_late_param(self.infcx.tcx, self.mir_def.to_def_id(), kind); let region_vid = { let name = r.get_name_or_anon(); self.infcx.next_nll_region_var(FR, || RegionCtxt::LateBound(name)) @@ -507,7 +501,12 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> { debug!(?region_vid); indices.insert_late_bound_region(r, region_vid.as_var()); } - }); + } + let inputs_and_output = self.infcx.replace_bound_regions_with_nll_infer_vars( + self.mir_def, + bound_inputs_and_output, + &indices, + ); let (unnormalized_output_ty, mut unnormalized_input_tys) = inputs_and_output.split_last().unwrap(); @@ -832,10 +831,9 @@ impl<'tcx> BorrowckInferCtxt<'tcx> { #[instrument(level = "debug", skip(self, indices))] fn replace_bound_regions_with_nll_infer_vars( &self, - origin: NllRegionVariableOrigin, all_outlive_scope: LocalDefId, value: ty::Binder<'tcx, T>, - indices: &mut UniversalRegionIndices<'tcx>, + indices: &UniversalRegionIndices<'tcx>, ) -> T where T: TypeFoldable>, @@ -845,18 +843,7 @@ impl<'tcx> BorrowckInferCtxt<'tcx> { let kind = ty::LateParamRegionKind::from_bound(br.var, br.kind); let liberated_region = ty::Region::new_late_param(self.tcx, all_outlive_scope.to_def_id(), kind); - let region_vid = { - let name = match br.kind.get_name() { - Some(name) => name, - _ => sym::anon, - }; - - self.next_nll_region_var(origin, || RegionCtxt::Bound(name)) - }; - - indices.insert_late_bound_region(liberated_region, region_vid.as_var()); - debug!(?liberated_region, ?region_vid); - region_vid + ty::Region::new_var(self.tcx, indices.to_region_vid(liberated_region)) }); value } @@ -870,7 +857,7 @@ impl<'tcx> UniversalRegionIndices<'tcx> { /// well. These are used for error reporting. fn insert_late_bound_region(&mut self, r: ty::Region<'tcx>, vid: ty::RegionVid) { debug!("insert_late_bound_region({:?}, {:?})", r, vid); - self.indices.insert(r, vid); + assert_eq!(self.indices.insert(r, vid), None); } /// Converts `r` into a local inference variable: `r` can either diff --git a/compiler/rustc_symbol_mangling/src/legacy.rs b/compiler/rustc_symbol_mangling/src/legacy.rs index 58c0a05df1f2c..879f3fac21fb4 100644 --- a/compiler/rustc_symbol_mangling/src/legacy.rs +++ b/compiler/rustc_symbol_mangling/src/legacy.rs @@ -19,15 +19,15 @@ pub(super) fn mangle<'tcx>( let def_id = instance.def_id(); // We want to compute the "type" of this item. Unfortunately, some - // kinds of items (e.g., closures) don't have an entry in the - // item-type array. So walk back up the find the closest parent - // that DOES have an entry. + // kinds of items (e.g., synthetic static allocations from const eval) + // don't have a proper implementation for the `type_of` query. So walk + // back up the find the closest parent that DOES have a type. let mut ty_def_id = def_id; let instance_ty; loop { let key = tcx.def_key(ty_def_id); match key.disambiguated_data.data { - DefPathData::TypeNs(_) | DefPathData::ValueNs(_) => { + DefPathData::TypeNs(_) | DefPathData::ValueNs(_) | DefPathData::Closure => { instance_ty = tcx.type_of(ty_def_id).instantiate_identity(); debug!(?instance_ty); break; diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index 1dcd0d0dfb830..da16a74209965 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -714,9 +714,18 @@ pub fn impossible_predicates<'tcx>(tcx: TyCtxt<'tcx>, predicates: Vec( diff --git a/src/bootstrap/src/core/build_steps/format.rs b/src/bootstrap/src/core/build_steps/format.rs index 40c908c3fa996..c7eafadee2df3 100644 --- a/src/bootstrap/src/core/build_steps/format.rs +++ b/src/bootstrap/src/core/build_steps/format.rs @@ -116,7 +116,7 @@ fn print_paths(verb: &str, adjective: Option<&str>, paths: &[String]) { println!("fmt: {verb} {len} {adjective}files"); } if len > 1000 && !CiEnv::is_ci() { - println!("hint: if this number seems too high, try running `git fetch origin master"); + println!("hint: if this number seems too high, try running `git fetch origin master`"); } } diff --git a/src/ci/docker/scripts/emscripten.sh b/src/ci/docker/scripts/emscripten.sh deleted file mode 100644 index 8b2b39ee1629e..0000000000000 --- a/src/ci/docker/scripts/emscripten.sh +++ /dev/null @@ -1,24 +0,0 @@ -#!/bin/sh -set -ex - -hide_output() { - set +x - on_err=" -echo ERROR: An error was encountered with the build. -cat /tmp/build.log -exit 1 -" - trap "$on_err" ERR - bash -c "while true; do sleep 30; echo \$(date) - building ...; done" & - PING_LOOP_PID=$! - "$@" &> /tmp/build.log - trap - ERR - kill $PING_LOOP_PID - rm -f /tmp/build.log - set -x -} - -git clone https://github.com/emscripten-core/emsdk.git /emsdk-portable -cd /emsdk-portable -hide_output ./emsdk install 3.1.68 -./emsdk activate 3.1.68 diff --git a/src/librustdoc/html/highlight.rs b/src/librustdoc/html/highlight.rs index 48a537ad5e7ad..62cf2b63f7fd6 100644 --- a/src/librustdoc/html/highlight.rs +++ b/src/librustdoc/html/highlight.rs @@ -337,7 +337,7 @@ enum Class { Ident(Span), Lifetime, PreludeTy(Span), - PreludeVal, + PreludeVal(Span), QuestionMark, Decoration(&'static str), } @@ -385,7 +385,7 @@ impl Class { Class::Ident(_) => "", Class::Lifetime => "lifetime", Class::PreludeTy(_) => "prelude-ty", - Class::PreludeVal => "prelude-val", + Class::PreludeVal(_) => "prelude-val", Class::QuestionMark => "question-mark", Class::Decoration(kind) => kind, } @@ -395,7 +395,11 @@ impl Class { /// a "span" (a tuple representing `(lo, hi)` equivalent of `Span`). fn get_span(self) -> Option { match self { - Self::Ident(sp) | Self::Self_(sp) | Self::Macro(sp) | Self::PreludeTy(sp) => Some(sp), + Self::Ident(sp) + | Self::Self_(sp) + | Self::Macro(sp) + | Self::PreludeTy(sp) + | Self::PreludeVal(sp) => Some(sp), Self::Comment | Self::DocComment | Self::Attribute @@ -406,7 +410,6 @@ impl Class { | Self::Number | Self::Bool | Self::Lifetime - | Self::PreludeVal | Self::QuestionMark | Self::Decoration(_) => None, } @@ -851,7 +854,9 @@ impl<'src> Classifier<'src> { TokenKind::Ident => match get_real_ident_class(text, false) { None => match text { "Option" | "Result" => Class::PreludeTy(self.new_span(before, text)), - "Some" | "None" | "Ok" | "Err" => Class::PreludeVal, + "Some" | "None" | "Ok" | "Err" => { + Class::PreludeVal(self.new_span(before, text)) + } // "union" is a weak keyword and is only considered as a keyword when declaring // a union type. "union" if self.check_if_is_union_keyword() => Class::KeyWord, diff --git a/src/librustdoc/html/render/span_map.rs b/src/librustdoc/html/render/span_map.rs index 26f75fa241cac..85f87f01afdf1 100644 --- a/src/librustdoc/html/render/span_map.rs +++ b/src/librustdoc/html/render/span_map.rs @@ -4,7 +4,7 @@ use rustc_data_structures::fx::{FxHashMap, FxIndexMap}; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{DefId, LOCAL_CRATE}; use rustc_hir::intravisit::{self, Visitor}; -use rustc_hir::{ExprKind, HirId, Item, ItemKind, Mod, Node}; +use rustc_hir::{ExprKind, HirId, Item, ItemKind, Mod, Node, Pat, PatKind, QPath}; use rustc_middle::hir::nested_filter; use rustc_middle::ty::TyCtxt; use rustc_span::hygiene::MacroKind; @@ -170,7 +170,7 @@ impl SpanMapVisitor<'_> { true } - fn handle_call(&mut self, hir_id: HirId, expr_hir_id: Option, span: Span) { + fn infer_id(&mut self, hir_id: HirId, expr_hir_id: Option, span: Span) { let hir = self.tcx.hir(); let body_id = hir.enclosing_body_owner(hir_id); // FIXME: this is showing error messages for parts of the code that are not @@ -189,6 +189,27 @@ impl SpanMapVisitor<'_> { self.matches.insert(span, link); } } + + fn handle_pat(&mut self, p: &Pat<'_>) { + match p.kind { + PatKind::Binding(_, _, _, Some(p)) => self.handle_pat(p), + PatKind::Struct(qpath, _, _) + | PatKind::TupleStruct(qpath, _, _) + | PatKind::Path(qpath) => match qpath { + QPath::TypeRelative(_, path) if matches!(path.res, Res::Err) => { + self.infer_id(path.hir_id, Some(p.hir_id), qpath.span()); + } + QPath::Resolved(_, path) => self.handle_path(path), + _ => {} + }, + PatKind::Or(pats) => { + for pat in pats { + self.handle_pat(pat); + } + } + _ => {} + } + } } impl<'tcx> Visitor<'tcx> for SpanMapVisitor<'tcx> { @@ -206,6 +227,10 @@ impl<'tcx> Visitor<'tcx> for SpanMapVisitor<'tcx> { intravisit::walk_path(self, path); } + fn visit_pat(&mut self, p: &Pat<'tcx>) { + self.handle_pat(p); + } + fn visit_mod(&mut self, m: &'tcx Mod<'tcx>, span: Span, id: HirId) { // To make the difference between "mod foo {}" and "mod foo;". In case we "import" another // file, we want to link to it. Otherwise no need to create a link. @@ -228,9 +253,9 @@ impl<'tcx> Visitor<'tcx> for SpanMapVisitor<'tcx> { fn visit_expr(&mut self, expr: &'tcx rustc_hir::Expr<'tcx>) { match expr.kind { ExprKind::MethodCall(segment, ..) => { - self.handle_call(segment.hir_id, Some(expr.hir_id), segment.ident.span) + self.infer_id(segment.hir_id, Some(expr.hir_id), segment.ident.span) } - ExprKind::Call(call, ..) => self.handle_call(call.hir_id, None, call.span), + ExprKind::Call(call, ..) => self.infer_id(call.hir_id, None, call.span), _ => { if self.handle_macro(expr.span) { // We don't want to go deeper into the macro. diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs index 7fcdfe3fb22ea..33166a395741c 100644 --- a/src/librustdoc/json/conversions.rs +++ b/src/librustdoc/json/conversions.rs @@ -622,7 +622,7 @@ impl FromClean for Type { impl FromClean for Path { fn from_clean(path: clean::Path, renderer: &JsonRenderer<'_>) -> Path { Path { - name: path.whole_name(), + name: path.last_opt().map_or(String::from(""), |s| String::from(s.as_str())), id: renderer.id_from_item_default(path.def_id().into()), args: path.segments.last().map(|args| Box::new(args.clone().args.into_json(renderer))), } diff --git a/src/rustdoc-json-types/lib.rs b/src/rustdoc-json-types/lib.rs index 84b33e3d86068..5a99977ded5eb 100644 --- a/src/rustdoc-json-types/lib.rs +++ b/src/rustdoc-json-types/lib.rs @@ -30,7 +30,7 @@ pub type FxHashMap = HashMap; // re-export for use in src/librustdoc /// This integer is incremented with every breaking change to the API, /// and is returned along with the JSON blob as [`Crate::format_version`]. /// Consuming code should assert that this value matches the format version(s) that it supports. -pub const FORMAT_VERSION: u32 = 37; +pub const FORMAT_VERSION: u32 = 38; /// The root of the emitted JSON blob. /// diff --git a/tests/codegen-units/item-collection/closures.rs b/tests/codegen-units/item-collection/closures.rs index 5fc8023092533..864f98817a874 100644 --- a/tests/codegen-units/item-collection/closures.rs +++ b/tests/codegen-units/item-collection/closures.rs @@ -10,3 +10,9 @@ pub async fn async_fn() {} pub fn closure() { let _ = || {}; } + +//~ MONO_ITEM fn A::{constant#0}::{closure#0} @@ +trait A where + [(); (|| {}, 1).1]: Sized, +{ +} diff --git a/tests/rustdoc-json/return_private.rs b/tests/rustdoc-json/return_private.rs index 0b341e2bda7d2..c238a536e0d8d 100644 --- a/tests/rustdoc-json/return_private.rs +++ b/tests/rustdoc-json/return_private.rs @@ -6,7 +6,7 @@ mod secret { } //@ has "$.index[*][?(@.name=='get_secret')].inner.function" -//@ is "$.index[*][?(@.name=='get_secret')].inner.function.sig.output.resolved_path.name" \"secret::Secret\" +//@ is "$.index[*][?(@.name=='get_secret')].inner.function.sig.output.resolved_path.name" \"Secret\" pub fn get_secret() -> secret::Secret { secret::Secret } diff --git a/tests/rustdoc/jump-to-def-pats.rs b/tests/rustdoc/jump-to-def-pats.rs new file mode 100644 index 0000000000000..147902b44cf5c --- /dev/null +++ b/tests/rustdoc/jump-to-def-pats.rs @@ -0,0 +1,52 @@ +// This test ensures that patterns also get a link generated. + +//@ compile-flags: -Zunstable-options --generate-link-to-definition + +#![crate_name = "foo"] + +//@ has 'src/foo/jump-to-def-pats.rs.html' + +use std::fmt; + +pub enum MyEnum { + Ok(T), + Err(E), + Some(T), + None, +} + +pub enum X { + A, +} + +pub fn foo() -> Result<(), ()> { + // FIXME: would be nice to be able to check both the class and the href at the same time so + // we could check the text as well... + //@ has - '//a[@class="prelude-val"]/@href' '{{channel}}/core/result/enum.Result.html#variant.Ok' + //@ has - '//a[@href="{{channel}}/core/result/enum.Result.html#variant.Ok"]' 'Ok' + Ok(()) +} + +impl fmt::Display for MyEnum { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + //@ has - '//a[@href="#12"]' 'Self::Ok' + Self::Ok(_) => f.write_str("MyEnum::Ok"), + //@ has - '//a[@href="#13"]' 'MyEnum::Err' + MyEnum::Err(_) => f.write_str("MyEnum::Err"), + //@ has - '//a[@href="#14"]' 'Self::Some' + Self::Some(_) => f.write_str("MyEnum::Some"), + //@ has - '//a[@href="#15"]' 'Self::None' + Self::None => f.write_str("MyEnum::None"), + } + } +} + +impl X { + fn p(&self) -> &str { + match self { + //@ has - '//a[@href="#19"]' 'Self::A' + Self::A => "X::A", + } + } +} diff --git a/tests/ui/closures/binder/nested-closures-regions.stderr b/tests/ui/closures/binder/nested-closures-regions.stderr index a30339ac67b1c..909cbcaa808a5 100644 --- a/tests/ui/closures/binder/nested-closures-regions.stderr +++ b/tests/ui/closures/binder/nested-closures-regions.stderr @@ -9,7 +9,7 @@ LL | for<'a> || -> () { for<'c> |_: &'a ()| -> () {}; }; extern "rust-call" fn((&(),)), (), ] - = note: late-bound region is '?4 + = note: late-bound region is '?3 = note: late-bound region is '?2 = note: number of external vids: 3 = note: where '?1: '?2 @@ -26,7 +26,7 @@ LL | for<'a> || -> () { for<'c> |_: &'a ()| -> () {}; }; extern "rust-call" fn(()), (), ] - = note: late-bound region is '?2 + = note: late-bound region is '?1 note: no external requirements --> $DIR/nested-closures-regions.rs:7:1 diff --git a/tests/ui/nll/closure-requirements/escape-argument-callee.stderr b/tests/ui/nll/closure-requirements/escape-argument-callee.stderr index a7a59dccf2234..a445534c8d801 100644 --- a/tests/ui/nll/closure-requirements/escape-argument-callee.stderr +++ b/tests/ui/nll/closure-requirements/escape-argument-callee.stderr @@ -17,7 +17,7 @@ LL | let mut closure = expect_sig(|p, y| *p = y); | - - ^^^^^^ assignment requires that `'1` must outlive `'2` | | | | | has type `&'1 i32` - | has type `&'?2 mut &'2 i32` + | has type `&'?1 mut &'2 i32` note: no external requirements --> $DIR/escape-argument-callee.rs:20:1 diff --git a/tests/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.stderr b/tests/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.stderr index 0094d7a50d369..621c1ea083b25 100644 --- a/tests/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.stderr +++ b/tests/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.stderr @@ -20,7 +20,7 @@ LL | foo(cell, |cell_a, cell_x| { LL | cell_a.set(cell_x.get()); // forces 'x: 'a, error in closure | ^^^^^^^^^^^^^^^^^^^^^^^^ `cell_x` escapes the closure body here | - = note: requirement occurs because of the type `Cell<&'?8 u32>`, which makes the generic argument `&'?8 u32` invariant + = note: requirement occurs because of the type `Cell<&'?9 u32>`, which makes the generic argument `&'?9 u32` invariant = note: the struct `Cell` is invariant over the parameter `T` = help: see for more information about variance diff --git a/tests/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-no-bounds.stderr b/tests/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-no-bounds.stderr index 4558ff50674f8..f48ed2823ddb1 100644 --- a/tests/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-no-bounds.stderr +++ b/tests/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-no-bounds.stderr @@ -16,9 +16,9 @@ error: lifetime may not live long enough --> $DIR/propagate-fail-to-approximate-longer-no-bounds.rs:37:9 | LL | establish_relationships(&cell_a, &cell_b, |_outlives, x, y| { - | --------- - has type `&'?7 Cell<&'1 u32>` + | --------- - has type `&'?6 Cell<&'1 u32>` | | - | has type `&'?5 Cell<&'2 &'?1 u32>` + | has type `&'?4 Cell<&'2 &'?1 u32>` LL | // Only works if 'x: 'y: LL | demand_y(x, y, x.get()) | ^^^^^^^^^^^^^^^^^^^^^^^ argument requires that `'1` must outlive `'2` diff --git a/tests/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-wrong-bounds.stderr b/tests/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-wrong-bounds.stderr index 83173ae80c00d..a090e94593fe6 100644 --- a/tests/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-wrong-bounds.stderr +++ b/tests/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-wrong-bounds.stderr @@ -16,9 +16,9 @@ error: lifetime may not live long enough --> $DIR/propagate-fail-to-approximate-longer-wrong-bounds.rs:41:9 | LL | establish_relationships(&cell_a, &cell_b, |_outlives1, _outlives2, x, y| { - | ---------- ---------- has type `&'?8 Cell<&'2 &'?2 u32>` + | ---------- ---------- has type `&'?7 Cell<&'2 &'?2 u32>` | | - | has type `&'?6 Cell<&'1 &'?1 u32>` + | has type `&'?5 Cell<&'1 &'?1 u32>` LL | // Only works if 'x: 'y: LL | demand_y(x, y, x.get()) | ^^^^^^^^^^^^^^^^^^^^^^^ argument requires that `'1` must outlive `'2` diff --git a/tests/ui/traits/trait-upcasting/impossible-method-modulo-binders-2.rs b/tests/ui/traits/trait-upcasting/impossible-method-modulo-binders-2.rs new file mode 100644 index 0000000000000..c03b5145aa73b --- /dev/null +++ b/tests/ui/traits/trait-upcasting/impossible-method-modulo-binders-2.rs @@ -0,0 +1,39 @@ +//@ build-pass +//@ revisions: current next +//@ ignore-compare-mode-next-solver (explicit revisions) +//@[next] compile-flags: -Znext-solver +// Regression test for #135462. +#![allow(coherence_leak_check)] + +type A = fn(&'static ()); +type B = fn(&()); + +trait Bound: From> { +} +impl Bound for String {} + +trait Trt { + fn __(&self, x: T) where T: Bound { + T::from(()); + } +} + +impl Trt for S {} + +type GetAssoc = ::Ty; + +trait WithAssoc { + type Ty; +} + +impl WithAssoc for B { + type Ty = String; +} + +impl WithAssoc for A { + type Ty = (); +} + +fn main() { + let x: &'static dyn Trt = &(); +} diff --git a/tests/ui/traits/trait-upcasting/impossible-method-modulo-binders.rs b/tests/ui/traits/trait-upcasting/impossible-method-modulo-binders.rs new file mode 100644 index 0000000000000..63ad1c0a06082 --- /dev/null +++ b/tests/ui/traits/trait-upcasting/impossible-method-modulo-binders.rs @@ -0,0 +1,40 @@ +//@ build-pass +//@ revisions: current next +//@ ignore-compare-mode-next-solver (explicit revisions) +//@[next] compile-flags: -Znext-solver + +trait Foo {} +impl Foo for fn(&'static ()) {} + +trait Bar { + type Assoc: Default; +} +impl Bar for T { + type Assoc = usize; +} +impl Bar for fn(&()) { + type Assoc = (); +} + +fn needs_foo() -> usize { + needs_bar::() +} + +fn needs_bar() -> ::Assoc { + Default::default() +} + +trait Evil { + fn bad(&self) + where + T: Foo, + { + needs_foo::(); + } +} + +impl Evil for () {} + +fn main() { + let x: &dyn Evil = &(); +}