diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5f9311635f6bf..7b9f87c079e3a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -369,35 +369,6 @@ jobs: env: DEPLOY_TOOLSTATES_JSON: toolstates-linux.json os: ubuntu-latest-xl - - name: dist-x86_64-apple - env: - SCRIPT: "./x.py dist" - RUST_CONFIGURE_ARGS: "--target=aarch64-apple-ios,x86_64-apple-ios --enable-full-tools --enable-sanitizers --enable-profiler --set rust.jemalloc" - RUSTC_RETRY_LINKER_ON_SEGFAULT: 1 - MACOSX_DEPLOYMENT_TARGET: 10.7 - NO_LLVM_ASSERTIONS: 1 - NO_DEBUG_ASSERTIONS: 1 - DIST_REQUIRE_ALL_TOOLS: 1 - os: macos-latest - - name: dist-x86_64-apple-alt - env: - SCRIPT: "./x.py dist" - RUST_CONFIGURE_ARGS: "--enable-extended --enable-profiler --set rust.jemalloc" - RUSTC_RETRY_LINKER_ON_SEGFAULT: 1 - MACOSX_DEPLOYMENT_TARGET: 10.7 - NO_LLVM_ASSERTIONS: 1 - NO_DEBUG_ASSERTIONS: 1 - os: macos-latest - - name: x86_64-apple - env: - SCRIPT: "./x.py test" - RUST_CONFIGURE_ARGS: "--build=x86_64-apple-darwin --enable-sanitizers --enable-profiler --set rust.jemalloc" - RUSTC_RETRY_LINKER_ON_SEGFAULT: 1 - MACOSX_DEPLOYMENT_TARGET: 10.8 - MACOSX_STD_DEPLOYMENT_TARGET: 10.7 - NO_LLVM_ASSERTIONS: 1 - NO_DEBUG_ASSERTIONS: 1 - os: macos-latest - name: x86_64-msvc-1 env: RUST_CONFIGURE_ARGS: "--build=x86_64-pc-windows-msvc --enable-profiler" @@ -580,6 +551,135 @@ jobs: AWS_ACCESS_KEY_ID: "${{ env.ARTIFACTS_AWS_ACCESS_KEY_ID }}" AWS_SECRET_ACCESS_KEY: "${{ secrets[format('AWS_SECRET_ACCESS_KEY_{0}', env.ARTIFACTS_AWS_ACCESS_KEY_ID)] }}" if: "success() && !env.SKIP_JOB && (github.event_name == 'push' || env.DEPLOY == '1' || env.DEPLOY_ALT == '1')" + auto-fallible: + name: auto-fallible + env: + CI_JOB_NAME: "${{ matrix.name }}" + SCCACHE_BUCKET: rust-lang-gha-caches + DEPLOY_BUCKET: rust-lang-gha + TOOLSTATE_REPO: "https://github.com/pietroalbini/rust-toolstate" + TOOLSTATE_ISSUES_API_URL: "https://github.com/gitapi/repos/pietroalbini/rust-toolstate/issues" + TOOLSTATE_PUBLISH: 1 + CACHES_AWS_ACCESS_KEY_ID: AKIA46X5W6CZOMUQATD5 + ARTIFACTS_AWS_ACCESS_KEY_ID: AKIA46X5W6CZH5AYXDVF + CACHE_DOMAIN: ci-caches-gha.rust-lang.org + if: "github.event_name == 'push' && github.ref == 'refs/heads/auto' && github.repository == 'rust-lang-ci/rust'" + strategy: + matrix: + include: + - name: dist-x86_64-apple + env: + SCRIPT: "./x.py dist" + RUST_CONFIGURE_ARGS: "--target=aarch64-apple-ios,x86_64-apple-ios --enable-full-tools --enable-sanitizers --enable-profiler --set rust.jemalloc" + RUSTC_RETRY_LINKER_ON_SEGFAULT: 1 + MACOSX_DEPLOYMENT_TARGET: 10.7 + NO_LLVM_ASSERTIONS: 1 + NO_DEBUG_ASSERTIONS: 1 + DIST_REQUIRE_ALL_TOOLS: 1 + os: macos-latest + - name: dist-x86_64-apple-alt + env: + SCRIPT: "./x.py dist" + RUST_CONFIGURE_ARGS: "--enable-extended --enable-profiler --set rust.jemalloc" + RUSTC_RETRY_LINKER_ON_SEGFAULT: 1 + MACOSX_DEPLOYMENT_TARGET: 10.7 + NO_LLVM_ASSERTIONS: 1 + NO_DEBUG_ASSERTIONS: 1 + os: macos-latest + - name: x86_64-apple + env: + SCRIPT: "./x.py test" + RUST_CONFIGURE_ARGS: "--build=x86_64-apple-darwin --enable-sanitizers --enable-profiler --set rust.jemalloc" + RUSTC_RETRY_LINKER_ON_SEGFAULT: 1 + MACOSX_DEPLOYMENT_TARGET: 10.8 + MACOSX_STD_DEPLOYMENT_TARGET: 10.7 + NO_LLVM_ASSERTIONS: 1 + NO_DEBUG_ASSERTIONS: 1 + os: macos-latest + timeout-minutes: 600 + runs-on: "${{ matrix.os }}" + steps: + - name: disable git crlf conversion + run: git config --global core.autocrlf false + shell: bash + - name: checkout the source code + uses: actions/checkout@v1 + with: + fetch-depth: 2 + - name: configure GitHub Actions to kill the build when outdated + uses: rust-lang/simpleinfra/github-actions/cancel-outdated-builds@master + with: + github_token: "${{ secrets.github_token }}" + if: "success() && !env.SKIP_JOB && github.ref != 'refs/heads/try'" + - name: add extra environment variables + run: src/ci/scripts/setup-environment.sh + env: + EXTRA_VARIABLES: "${{ toJson(matrix.env) }}" + if: success() && !env.SKIP_JOB + - name: decide whether to skip this job + run: src/ci/scripts/should-skip-this.sh + if: success() && !env.SKIP_JOB + - name: collect CPU statistics + run: src/ci/scripts/collect-cpu-stats.sh + if: success() && !env.SKIP_JOB + - name: show the current environment + run: src/ci/scripts/dump-environment.sh + if: success() && !env.SKIP_JOB + - name: install awscli + run: src/ci/scripts/install-awscli.sh + if: success() && !env.SKIP_JOB + - name: install sccache + run: src/ci/scripts/install-sccache.sh + if: success() && !env.SKIP_JOB + - name: install clang + run: src/ci/scripts/install-clang.sh + if: success() && !env.SKIP_JOB + - name: install WIX + run: src/ci/scripts/install-wix.sh + if: success() && !env.SKIP_JOB + - name: install InnoSetup + run: src/ci/scripts/install-innosetup.sh + if: success() && !env.SKIP_JOB + - name: ensure the build happens on a partition with enough space + run: src/ci/scripts/symlink-build-dir.sh + if: success() && !env.SKIP_JOB + - name: disable git crlf conversion + run: src/ci/scripts/disable-git-crlf-conversion.sh + if: success() && !env.SKIP_JOB + - name: install MSYS2 + run: src/ci/scripts/install-msys2.sh + if: success() && !env.SKIP_JOB + - name: install MinGW + run: src/ci/scripts/install-mingw.sh + if: success() && !env.SKIP_JOB + - name: install ninja + run: src/ci/scripts/install-ninja.sh + if: success() && !env.SKIP_JOB + - name: enable ipv6 on Docker + run: src/ci/scripts/enable-docker-ipv6.sh + if: success() && !env.SKIP_JOB + - name: disable git crlf conversion + run: src/ci/scripts/disable-git-crlf-conversion.sh + if: success() && !env.SKIP_JOB + - name: checkout submodules + run: src/ci/scripts/checkout-submodules.sh + if: success() && !env.SKIP_JOB + - name: ensure line endings are correct + run: src/ci/scripts/verify-line-endings.sh + if: success() && !env.SKIP_JOB + - name: run the build + run: src/ci/scripts/run-build-from-ci.sh + env: + AWS_ACCESS_KEY_ID: "${{ env.CACHES_AWS_ACCESS_KEY_ID }}" + AWS_SECRET_ACCESS_KEY: "${{ secrets[format('AWS_SECRET_ACCESS_KEY_{0}', env.CACHES_AWS_ACCESS_KEY_ID)] }}" + TOOLSTATE_REPO_ACCESS_TOKEN: "${{ secrets.TOOLSTATE_REPO_ACCESS_TOKEN }}" + if: success() && !env.SKIP_JOB + - name: upload artifacts to S3 + run: src/ci/scripts/upload-artifacts.sh + env: + AWS_ACCESS_KEY_ID: "${{ env.ARTIFACTS_AWS_ACCESS_KEY_ID }}" + AWS_SECRET_ACCESS_KEY: "${{ secrets[format('AWS_SECRET_ACCESS_KEY_{0}', env.ARTIFACTS_AWS_ACCESS_KEY_ID)] }}" + if: "success() && !env.SKIP_JOB && (github.event_name == 'push' || env.DEPLOY == '1' || env.DEPLOY_ALT == '1')" master: name: master runs-on: ubuntu-latest diff --git a/src/ci/github-actions/ci.yml b/src/ci/github-actions/ci.yml index daa2d55c04399..5e67567c76b4f 100644 --- a/src/ci/github-actions/ci.yml +++ b/src/ci/github-actions/ci.yml @@ -414,42 +414,6 @@ jobs: DEPLOY_TOOLSTATES_JSON: toolstates-linux.json <<: *job-linux-xl - #################### - # macOS Builders # - #################### - - - name: dist-x86_64-apple - env: - SCRIPT: ./x.py dist - RUST_CONFIGURE_ARGS: --target=aarch64-apple-ios,x86_64-apple-ios --enable-full-tools --enable-sanitizers --enable-profiler --set rust.jemalloc - RUSTC_RETRY_LINKER_ON_SEGFAULT: 1 - MACOSX_DEPLOYMENT_TARGET: 10.7 - NO_LLVM_ASSERTIONS: 1 - NO_DEBUG_ASSERTIONS: 1 - DIST_REQUIRE_ALL_TOOLS: 1 - <<: *job-macos-xl - - - name: dist-x86_64-apple-alt - env: - SCRIPT: ./x.py dist - RUST_CONFIGURE_ARGS: --enable-extended --enable-profiler --set rust.jemalloc - RUSTC_RETRY_LINKER_ON_SEGFAULT: 1 - MACOSX_DEPLOYMENT_TARGET: 10.7 - NO_LLVM_ASSERTIONS: 1 - NO_DEBUG_ASSERTIONS: 1 - <<: *job-macos-xl - - - name: x86_64-apple - env: - SCRIPT: ./x.py test - RUST_CONFIGURE_ARGS: --build=x86_64-apple-darwin --enable-sanitizers --enable-profiler --set rust.jemalloc - RUSTC_RETRY_LINKER_ON_SEGFAULT: 1 - MACOSX_DEPLOYMENT_TARGET: 10.8 - MACOSX_STD_DEPLOYMENT_TARGET: 10.7 - NO_LLVM_ASSERTIONS: 1 - NO_DEBUG_ASSERTIONS: 1 - <<: *job-macos-xl - ###################### # Windows Builders # ###################### @@ -595,6 +559,51 @@ jobs: SCRIPT: python x.py dist <<: *job-windows-xl + auto-fallible: + <<: *base-ci-job + name: auto-fallible + env: + <<: [*shared-ci-variables, *prod-variables] + if: github.event_name == 'push' && github.ref == 'refs/heads/auto' && github.repository == 'rust-lang-ci/rust' + strategy: + matrix: + include: + #################### + # macOS Builders # + #################### + + - name: dist-x86_64-apple + env: + SCRIPT: ./x.py dist + RUST_CONFIGURE_ARGS: --target=aarch64-apple-ios,x86_64-apple-ios --enable-full-tools --enable-sanitizers --enable-profiler --set rust.jemalloc + RUSTC_RETRY_LINKER_ON_SEGFAULT: 1 + MACOSX_DEPLOYMENT_TARGET: 10.7 + NO_LLVM_ASSERTIONS: 1 + NO_DEBUG_ASSERTIONS: 1 + DIST_REQUIRE_ALL_TOOLS: 1 + <<: *job-macos-xl + + - name: dist-x86_64-apple-alt + env: + SCRIPT: ./x.py dist + RUST_CONFIGURE_ARGS: --enable-extended --enable-profiler --set rust.jemalloc + RUSTC_RETRY_LINKER_ON_SEGFAULT: 1 + MACOSX_DEPLOYMENT_TARGET: 10.7 + NO_LLVM_ASSERTIONS: 1 + NO_DEBUG_ASSERTIONS: 1 + <<: *job-macos-xl + + - name: x86_64-apple + env: + SCRIPT: ./x.py test + RUST_CONFIGURE_ARGS: --build=x86_64-apple-darwin --enable-sanitizers --enable-profiler --set rust.jemalloc + RUSTC_RETRY_LINKER_ON_SEGFAULT: 1 + MACOSX_DEPLOYMENT_TARGET: 10.8 + MACOSX_STD_DEPLOYMENT_TARGET: 10.7 + NO_LLVM_ASSERTIONS: 1 + NO_DEBUG_ASSERTIONS: 1 + <<: *job-macos-xl + master: name: master runs-on: ubuntu-latest diff --git a/src/libcore/result.rs b/src/libcore/result.rs index 2080ae193667e..0c0e6d291bb92 100644 --- a/src/libcore/result.rs +++ b/src/libcore/result.rs @@ -1155,6 +1155,7 @@ impl Result { /// # Examples /// /// ``` + /// #![feature(inner_deref)] /// let x: Result = Ok("hello".to_string()); /// let y: Result<&str, &u32> = Ok("hello"); /// assert_eq!(x.as_deref(), y); @@ -1189,12 +1190,15 @@ impl Result { /// # Examples /// /// ``` + /// #![feature(inner_deref)] + /// let mut s = "HELLO".to_string(); /// let mut x: Result = Ok("hello".to_string()); - /// let y: Result<&mut str, &mut u32> = Ok("HELLO"); + /// let y: Result<&mut str, &mut u32> = Ok(&mut s); /// assert_eq!(x.as_deref_mut().map(|x| { x.make_ascii_uppercase(); x }), y); /// + /// let mut i = 42; /// let mut x: Result = Err(42); - /// let y: Result<&mut str, &mut u32> = Err(&42); + /// let y: Result<&mut str, &mut u32> = Err(&mut i); /// assert_eq!(x.as_deref_mut().map(|x| { x.make_ascii_uppercase(); x }), y); /// ``` pub fn as_deref_mut(&mut self) -> Result<&mut T::Target, &mut E> { diff --git a/src/libcore/time.rs b/src/libcore/time.rs index e2ceaf80c0cda..3b6dafeee2540 100644 --- a/src/libcore/time.rs +++ b/src/libcore/time.rs @@ -31,7 +31,7 @@ const MICROS_PER_SEC: u64 = 1_000_000; /// the number of nanoseconds. /// /// `Duration`s implement many common traits, including [`Add`], [`Sub`], and other -/// [`ops`] traits. +/// [`ops`] traits. It implements `Default` by returning a zero-length `Duration`. /// /// [`Add`]: ../../std/ops/trait.Add.html /// [`Sub`]: ../../std/ops/trait.Sub.html @@ -138,6 +138,24 @@ impl Duration { Duration { secs, nanos } } + /// Creates a new `Duration` that spans no time. + /// + /// # Examples + /// + /// ``` + /// #![feature(duration_zero)] + /// use std::time::Duration; + /// + /// let duration = Duration::zero(); + /// assert!(duration.is_zero()); + /// assert_eq!(duration.as_nanos(), 0); + /// ``` + #[unstable(feature = "duration_zero", issue = "73544")] + #[inline] + pub const fn zero() -> Duration { + Duration { secs: 0, nanos: 0 } + } + /// Creates a new `Duration` from the specified number of whole seconds. /// /// # Examples @@ -223,6 +241,29 @@ impl Duration { } } + /// Returns true if this `Duration` spans no time. + /// + /// # Examples + /// + /// ``` + /// #![feature(duration_zero)] + /// use std::time::Duration; + /// + /// assert!(Duration::zero().is_zero()); + /// assert!(Duration::new(0, 0).is_zero()); + /// assert!(Duration::from_nanos(0).is_zero()); + /// assert!(Duration::from_secs(0).is_zero()); + /// + /// assert!(!Duration::new(1, 1).is_zero()); + /// assert!(!Duration::from_nanos(1).is_zero()); + /// assert!(!Duration::from_secs(1).is_zero()); + /// ``` + #[unstable(feature = "duration_zero", issue = "73544")] + #[inline] + pub const fn is_zero(&self) -> bool { + self.secs == 0 && self.nanos == 0 + } + /// Returns the number of _whole_ seconds contained by this `Duration`. /// /// The returned value does not include the fractional (nanosecond) part of the diff --git a/src/librustc_arena/lib.rs b/src/librustc_arena/lib.rs index 6cf2db3e2da49..5cf4f97fb8863 100644 --- a/src/librustc_arena/lib.rs +++ b/src/librustc_arena/lib.rs @@ -611,7 +611,11 @@ macro_rules! which_arena_for_type { #[macro_export] macro_rules! declare_arena { - ([], [$($a:tt $name:ident: $ty:ty, $gen_ty:ty;)*], $tcx:lifetime) => { + // This macro has to take the same input as + // `impl_arena_allocatable_decoders` which requires a second version of + // each type. We ignore that type until we can fix + // `impl_arena_allocatable_decoders`. + ([], [$($a:tt $name:ident: $ty:ty, $_gen_ty:ty;)*], $tcx:lifetime) => { #[derive(Default)] pub struct Arena<$tcx> { pub dropless: $crate::DroplessArena, @@ -619,39 +623,56 @@ macro_rules! declare_arena { $($name: $crate::arena_for_type!($a[$ty]),)* } - #[marker] - pub trait ArenaAllocatable<'tcx> {} - - impl<'tcx, T: Copy> ArenaAllocatable<'tcx> for T {} - - unsafe trait ArenaField<'tcx>: Sized + ArenaAllocatable<'tcx> { - /// Returns a specific arena to allocate from. - /// If `None` is returned, the `DropArena` will be used. - fn arena<'a>(arena: &'a Arena<'tcx>) -> Option<&'a $crate::TypedArena>; + pub trait ArenaAllocatable<'tcx, T = Self>: Sized { + fn allocate_on<'a>(self, arena: &'a Arena<'tcx>) -> &'a mut Self; + fn allocate_from_iter<'a>( + arena: &'a Arena<'tcx>, + iter: impl ::std::iter::IntoIterator, + ) -> &'a mut [Self]; } - unsafe impl<'tcx, T: ArenaAllocatable<'tcx>> ArenaField<'tcx> for T { + impl<'tcx, T: Copy> ArenaAllocatable<'tcx, ()> for T { #[inline] - default fn arena<'a>(_: &'a Arena<'tcx>) -> Option<&'a $crate::TypedArena> { - panic!() + fn allocate_on<'a>(self, arena: &'a Arena<'tcx>) -> &'a mut Self { + arena.dropless.alloc(self) + } + #[inline] + fn allocate_from_iter<'a>( + arena: &'a Arena<'tcx>, + iter: impl ::std::iter::IntoIterator, + ) -> &'a mut [Self] { + arena.dropless.alloc_from_iter(iter) } - } + } $( - #[allow(unused_lifetimes)] - impl<$tcx> ArenaAllocatable<$tcx> for $ty {} - unsafe impl<$tcx, '_x, '_y, '_z, '_w> ArenaField<$tcx> for $gen_ty where Self: ArenaAllocatable<$tcx> { + impl<$tcx> ArenaAllocatable<$tcx, $ty> for $ty { #[inline] - fn arena<'a>(_arena: &'a Arena<$tcx>) -> Option<&'a $crate::TypedArena> { - // SAFETY: We only implement `ArenaAllocatable<$tcx>` for - // `$ty`, so `$ty` and Self are the same type - unsafe { - ::std::mem::transmute::< - Option<&'a $crate::TypedArena<$ty>>, - Option<&'a $crate::TypedArena>, - >( - $crate::which_arena_for_type!($a[&_arena.$name]) - ) + fn allocate_on<'a>(self, arena: &'a Arena<$tcx>) -> &'a mut Self { + if !::std::mem::needs_drop::() { + return arena.dropless.alloc(self); + } + match $crate::which_arena_for_type!($a[&arena.$name]) { + ::std::option::Option::<&$crate::TypedArena>::Some(ty_arena) => { + ty_arena.alloc(self) + } + ::std::option::Option::None => unsafe { arena.drop.alloc(self) }, + } + } + + #[inline] + fn allocate_from_iter<'a>( + arena: &'a Arena<$tcx>, + iter: impl ::std::iter::IntoIterator, + ) -> &'a mut [Self] { + if !::std::mem::needs_drop::() { + return arena.dropless.alloc_from_iter(iter); + } + match $crate::which_arena_for_type!($a[&arena.$name]) { + ::std::option::Option::<&$crate::TypedArena>::Some(ty_arena) => { + ty_arena.alloc_from_iter(iter) + } + ::std::option::Option::None => unsafe { arena.drop.alloc_from_iter(iter) }, } } } @@ -659,14 +680,8 @@ macro_rules! declare_arena { impl<'tcx> Arena<'tcx> { #[inline] - pub fn alloc>(&self, value: T) -> &mut T { - if !::std::mem::needs_drop::() { - return self.dropless.alloc(value); - } - match >::arena(self) { - ::std::option::Option::Some(arena) => arena.alloc(value), - ::std::option::Option::None => unsafe { self.drop.alloc(value) }, - } + pub fn alloc, U>(&self, value: T) -> &mut T { + value.allocate_on(self) } #[inline] @@ -677,17 +692,11 @@ macro_rules! declare_arena { self.dropless.alloc_slice(value) } - pub fn alloc_from_iter<'a, T: ArenaAllocatable<'tcx>>( + pub fn alloc_from_iter<'a, T: ArenaAllocatable<'tcx, U>, U>( &'a self, iter: impl ::std::iter::IntoIterator, ) -> &'a mut [T] { - if !::std::mem::needs_drop::() { - return self.dropless.alloc_from_iter(iter); - } - match >::arena(self) { - ::std::option::Option::Some(arena) => arena.alloc_from_iter(iter), - ::std::option::Option::None => unsafe { self.drop.alloc_from_iter(iter) }, - } + T::allocate_from_iter(self, iter) } } } diff --git a/src/librustc_ast_lowering/lib.rs b/src/librustc_ast_lowering/lib.rs index a722a88a7a102..335cc3e61040d 100644 --- a/src/librustc_ast_lowering/lib.rs +++ b/src/librustc_ast_lowering/lib.rs @@ -32,8 +32,6 @@ #![feature(array_value_iter)] #![feature(crate_visibility_modifier)] -#![feature(marker_trait_attr)] -#![feature(min_specialization)] #![feature(or_patterns)] #![recursion_limit = "256"] @@ -205,6 +203,8 @@ pub trait Resolver { fn lint_buffer(&mut self) -> &mut LintBuffer; fn next_node_id(&mut self) -> NodeId; + + fn trait_map(&self) -> &NodeMap>; } type NtToTokenstream = fn(&Nonterminal, &ParseSess, Span) -> TokenStream; @@ -557,6 +557,13 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { let proc_macros = c.proc_macros.iter().map(|id| self.node_id_to_hir_id[*id].unwrap()).collect(); + let trait_map = self + .resolver + .trait_map() + .iter() + .map(|(&k, v)| (self.node_id_to_hir_id[k].unwrap(), v.clone())) + .collect(); + self.resolver.definitions().init_node_id_to_hir_id_mapping(self.node_id_to_hir_id); hir::Crate { @@ -571,6 +578,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { trait_impls: self.trait_impls, modules: self.modules, proc_macros, + trait_map, } } diff --git a/src/librustc_builtin_macros/asm.rs b/src/librustc_builtin_macros/asm.rs index 2988567960464..52f86aa7e06b9 100644 --- a/src/librustc_builtin_macros/asm.rs +++ b/src/librustc_builtin_macros/asm.rs @@ -16,7 +16,7 @@ struct AsmArgs { named_args: FxHashMap, reg_args: FxHashSet, options: ast::InlineAsmOptions, - options_span: Option, + options_spans: Vec, } fn parse_args<'a>( @@ -59,7 +59,7 @@ fn parse_args<'a>( named_args: FxHashMap::default(), reg_args: FxHashSet::default(), options: ast::InlineAsmOptions::empty(), - options_span: None, + options_spans: vec![], }; let mut allow_templates = true; @@ -174,9 +174,9 @@ fn parse_args<'a>( // Validate the order of named, positional & explicit register operands and options. We do // this at the end once we have the full span of the argument available. - if let Some(options_span) = args.options_span { + if !args.options_spans.is_empty() { ecx.struct_span_err(span, "arguments are not allowed after options") - .span_label(options_span, "previous options") + .span_labels(args.options_spans.clone(), "previous options") .span_label(span, "argument") .emit(); } @@ -227,23 +227,23 @@ fn parse_args<'a>( if args.options.contains(ast::InlineAsmOptions::NOMEM) && args.options.contains(ast::InlineAsmOptions::READONLY) { - let span = args.options_span.unwrap(); - ecx.struct_span_err(span, "the `nomem` and `readonly` options are mutually exclusive") + let spans = args.options_spans.clone(); + ecx.struct_span_err(spans, "the `nomem` and `readonly` options are mutually exclusive") .emit(); } if args.options.contains(ast::InlineAsmOptions::PURE) && args.options.contains(ast::InlineAsmOptions::NORETURN) { - let span = args.options_span.unwrap(); - ecx.struct_span_err(span, "the `pure` and `noreturn` options are mutually exclusive") + let spans = args.options_spans.clone(); + ecx.struct_span_err(spans, "the `pure` and `noreturn` options are mutually exclusive") .emit(); } if args.options.contains(ast::InlineAsmOptions::PURE) && !args.options.intersects(ast::InlineAsmOptions::NOMEM | ast::InlineAsmOptions::READONLY) { - let span = args.options_span.unwrap(); + let spans = args.options_spans.clone(); ecx.struct_span_err( - span, + spans, "the `pure` option must be combined with either `nomem` or `readonly`", ) .emit(); @@ -267,7 +267,7 @@ fn parse_args<'a>( } if args.options.contains(ast::InlineAsmOptions::PURE) && !have_real_output { ecx.struct_span_err( - args.options_span.unwrap(), + args.options_spans.clone(), "asm with `pure` option must have at least one output", ) .emit(); @@ -283,6 +283,50 @@ fn parse_args<'a>( Ok(args) } +/// Report a duplicate option error. +/// +/// This function must be called immediately after the option token is parsed. +/// Otherwise, the suggestion will be incorrect. +fn err_duplicate_option<'a>(p: &mut Parser<'a>, symbol: Symbol, span: Span) { + let mut err = p + .sess + .span_diagnostic + .struct_span_err(span, &format!("the `{}` option was already provided", symbol)); + err.span_label(span, "this option was already provided"); + + // Tool-only output + let mut full_span = span; + if p.token.kind == token::Comma { + full_span = full_span.to(p.token.span); + } + err.tool_only_span_suggestion( + full_span, + "remove this option", + String::new(), + Applicability::MachineApplicable, + ); + + err.emit(); +} + +/// Try to set the provided option in the provided `AsmArgs`. +/// If it is already set, report a duplicate option error. +/// +/// This function must be called immediately after the option token is parsed. +/// Otherwise, the error will not point to the correct spot. +fn try_set_option<'a>( + p: &mut Parser<'a>, + args: &mut AsmArgs, + symbol: Symbol, + option: ast::InlineAsmOptions, +) { + if !args.options.contains(option) { + args.options |= option; + } else { + err_duplicate_option(p, symbol, p.prev_token.span); + } +} + fn parse_options<'a>(p: &mut Parser<'a>, args: &mut AsmArgs) -> Result<(), DiagnosticBuilder<'a>> { let span_start = p.prev_token.span; @@ -290,20 +334,20 @@ fn parse_options<'a>(p: &mut Parser<'a>, args: &mut AsmArgs) -> Result<(), Diagn while !p.eat(&token::CloseDelim(token::DelimToken::Paren)) { if p.eat(&token::Ident(sym::pure, false)) { - args.options |= ast::InlineAsmOptions::PURE; + try_set_option(p, args, sym::pure, ast::InlineAsmOptions::PURE); } else if p.eat(&token::Ident(sym::nomem, false)) { - args.options |= ast::InlineAsmOptions::NOMEM; + try_set_option(p, args, sym::nomem, ast::InlineAsmOptions::NOMEM); } else if p.eat(&token::Ident(sym::readonly, false)) { - args.options |= ast::InlineAsmOptions::READONLY; + try_set_option(p, args, sym::readonly, ast::InlineAsmOptions::READONLY); } else if p.eat(&token::Ident(sym::preserves_flags, false)) { - args.options |= ast::InlineAsmOptions::PRESERVES_FLAGS; + try_set_option(p, args, sym::preserves_flags, ast::InlineAsmOptions::PRESERVES_FLAGS); } else if p.eat(&token::Ident(sym::noreturn, false)) { - args.options |= ast::InlineAsmOptions::NORETURN; + try_set_option(p, args, sym::noreturn, ast::InlineAsmOptions::NORETURN); } else if p.eat(&token::Ident(sym::nostack, false)) { - args.options |= ast::InlineAsmOptions::NOSTACK; + try_set_option(p, args, sym::nostack, ast::InlineAsmOptions::NOSTACK); } else { p.expect(&token::Ident(sym::att_syntax, false))?; - args.options |= ast::InlineAsmOptions::ATT_SYNTAX; + try_set_option(p, args, sym::att_syntax, ast::InlineAsmOptions::ATT_SYNTAX); } // Allow trailing commas @@ -314,14 +358,7 @@ fn parse_options<'a>(p: &mut Parser<'a>, args: &mut AsmArgs) -> Result<(), Diagn } let new_span = span_start.to(p.prev_token.span); - if let Some(options_span) = args.options_span { - p.struct_span_err(new_span, "asm options cannot be specified multiple times") - .span_label(options_span, "previously here") - .span_label(new_span, "duplicate options") - .emit(); - } else { - args.options_span = Some(new_span); - } + args.options_spans.push(new_span); Ok(()) } diff --git a/src/librustc_hir/definitions.rs b/src/librustc_hir/definitions.rs index b63dd653c4dd8..5755a3db92ac1 100644 --- a/src/librustc_hir/definitions.rs +++ b/src/librustc_hir/definitions.rs @@ -81,14 +81,13 @@ pub struct Definitions { def_id_to_span: IndexVec, - // FIXME(eddyb) don't go through `ast::NodeId` to convert between `HirId` - // and `LocalDefId` - ideally all `LocalDefId`s would be HIR owners. node_id_to_def_id: FxHashMap, def_id_to_node_id: IndexVec, - pub(super) node_id_to_hir_id: IndexVec>, - /// The reverse mapping of `node_id_to_hir_id`. - pub(super) hir_id_to_node_id: FxHashMap, + // FIXME(eddyb) ideally all `LocalDefId`s would be HIR owners. + pub(super) def_id_to_hir_id: IndexVec>, + /// The reverse mapping of `def_id_to_hir_id`. + pub(super) hir_id_to_def_id: FxHashMap, /// If `ExpnId` is an ID of some macro expansion, /// then `DefId` is the normal module (`mod`) in which the expanded macro was defined. @@ -327,9 +326,7 @@ impl Definitions { #[inline] pub fn local_def_id(&self, node: ast::NodeId) -> LocalDefId { - self.opt_local_def_id(node).unwrap_or_else(|| { - panic!("no entry for node id: `{:?}` / `{:?}`", node, self.opt_node_id_to_hir_id(node)) - }) + self.opt_local_def_id(node).unwrap_or_else(|| panic!("no entry for node id: `{:?}`", node)) } #[inline] @@ -337,37 +334,19 @@ impl Definitions { self.local_def_id_to_hir_id(def_id) } - #[inline] - pub fn hir_id_to_node_id(&self, hir_id: hir::HirId) -> ast::NodeId { - self.hir_id_to_node_id[&hir_id] - } - - #[inline] - pub fn node_id_to_hir_id(&self, node_id: ast::NodeId) -> hir::HirId { - self.node_id_to_hir_id[node_id].unwrap() - } - - #[inline] - pub fn opt_node_id_to_hir_id(&self, node_id: ast::NodeId) -> Option { - self.node_id_to_hir_id[node_id] - } - #[inline] pub fn local_def_id_to_hir_id(&self, id: LocalDefId) -> hir::HirId { - let node_id = self.def_id_to_node_id[id]; - self.node_id_to_hir_id[node_id].unwrap() + self.def_id_to_hir_id[id].unwrap() } #[inline] pub fn opt_local_def_id_to_hir_id(&self, id: LocalDefId) -> Option { - let node_id = self.def_id_to_node_id[id]; - self.node_id_to_hir_id[node_id] + self.def_id_to_hir_id[id] } #[inline] pub fn opt_hir_id_to_local_def_id(&self, hir_id: hir::HirId) -> Option { - let node_id = self.hir_id_to_node_id(hir_id); - self.opt_local_def_id(node_id) + self.hir_id_to_def_id.get(&hir_id).copied() } /// Retrieves the span of the given `DefId` if `DefId` is in the local crate. @@ -477,16 +456,24 @@ impl Definitions { mapping: IndexVec>, ) { assert!( - self.node_id_to_hir_id.is_empty(), - "trying to initialize `NodeId` -> `HirId` mapping twice" + self.def_id_to_hir_id.is_empty(), + "trying to initialize `LocalDefId` <-> `HirId` mappings twice" ); - self.node_id_to_hir_id = mapping; - // Build the reverse mapping of `node_id_to_hir_id`. - self.hir_id_to_node_id = self - .node_id_to_hir_id - .iter_enumerated() - .filter_map(|(node_id, &hir_id)| hir_id.map(|hir_id| (hir_id, node_id))) + self.def_id_to_hir_id = self + .def_id_to_node_id + .iter() + .map(|&node_id| mapping.get(node_id).and_then(|&hir_id| hir_id)) + .collect(); + + // Build the reverse mapping of `def_id_to_hir_id`. + self.hir_id_to_def_id = mapping + .into_iter_enumerated() + .filter_map(|(node_id, hir_id)| { + hir_id.and_then(|hir_id| { + self.node_id_to_def_id.get(&node_id).map(|&def_id| (hir_id, def_id)) + }) + }) .collect(); } diff --git a/src/librustc_hir/hir.rs b/src/librustc_hir/hir.rs index eb1db46fd2bda..7d1cb7738c35e 100644 --- a/src/librustc_hir/hir.rs +++ b/src/librustc_hir/hir.rs @@ -639,6 +639,8 @@ pub struct Crate<'hir> { /// A list of proc macro HirIds, written out in the order in which /// they are declared in the static array generated by proc_macro_harness. pub proc_macros: Vec, + + pub trait_map: BTreeMap>, } impl Crate<'hir> { @@ -2651,7 +2653,7 @@ pub type CaptureModeMap = NodeMap; // The TraitCandidate's import_ids is empty if the trait is defined in the same module, and // has length > 0 if the trait is found through an chain of imports, starting with the // import/use statement in the scope where the trait is used. -#[derive(Clone, Debug)] +#[derive(RustcEncodable, RustcDecodable, Clone, Debug)] pub struct TraitCandidate { pub def_id: DefId, pub import_ids: SmallVec<[LocalDefId; 1]>, diff --git a/src/librustc_infer/infer/outlives/verify.rs b/src/librustc_infer/infer/outlives/verify.rs index 82d32b008088d..383979f864075 100644 --- a/src/librustc_infer/infer/outlives/verify.rs +++ b/src/librustc_infer/infer/outlives/verify.rs @@ -1,9 +1,8 @@ use crate::infer::outlives::env::RegionBoundPairs; use crate::infer::{GenericKind, VerifyBound}; -use crate::traits; use rustc_data_structures::captures::Captures; use rustc_hir::def_id::DefId; -use rustc_middle::ty::subst::{GenericArg, GenericArgKind, InternalSubsts, Subst}; +use rustc_middle::ty::subst::{GenericArg, GenericArgKind, Subst}; use rustc_middle::ty::{self, Ty, TyCtxt}; /// The `TypeOutlives` struct has the job of "lowering" a `T: 'a` @@ -311,18 +310,14 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> { fn region_bounds_declared_on_associated_item( &self, assoc_item_def_id: DefId, - ) -> impl Iterator> + 'cx + Captures<'tcx> { + ) -> impl Iterator> { let tcx = self.tcx; - let assoc_item = tcx.associated_item(assoc_item_def_id); - let trait_def_id = assoc_item.container.assert_trait(); - let trait_predicates = tcx.predicates_of(trait_def_id).predicates.iter().map(|(p, _)| *p); - let identity_substs = InternalSubsts::identity_for_item(tcx, assoc_item_def_id); - let identity_proj = tcx.mk_projection(assoc_item_def_id, identity_substs); - self.collect_outlives_from_predicate_list( - move |ty| ty == identity_proj, - traits::elaborate_predicates(tcx, trait_predicates).map(|o| o.predicate), - ) - .map(|b| b.1) + let predicates = tcx.projection_predicates(assoc_item_def_id); + predicates + .into_iter() + .filter_map(|p| p.to_opt_type_outlives()) + .filter_map(|p| p.no_bound_vars()) + .map(|b| b.1) } /// Searches through a predicate list for a predicate `T: 'a`. diff --git a/src/librustc_infer/traits/mod.rs b/src/librustc_infer/traits/mod.rs index 47555aca9f3fb..8cd1eb9957bed 100644 --- a/src/librustc_infer/traits/mod.rs +++ b/src/librustc_infer/traits/mod.rs @@ -25,8 +25,6 @@ pub use self::project::{ Normalized, NormalizedTy, ProjectionCache, ProjectionCacheEntry, ProjectionCacheKey, ProjectionCacheStorage, Reveal, }; -crate use self::util::elaborate_predicates; - pub use rustc_middle::traits::*; /// An `Obligation` represents some trait reference (e.g., `i32: Eq`) for diff --git a/src/librustc_lint/types.rs b/src/librustc_lint/types.rs index d92c1131ff9fd..a19c9a3557996 100644 --- a/src/librustc_lint/types.rs +++ b/src/librustc_lint/types.rs @@ -895,22 +895,33 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { } fn check_for_opaque_ty(&mut self, sp: Span, ty: Ty<'tcx>) -> bool { - struct ProhibitOpaqueTypes<'tcx> { + struct ProhibitOpaqueTypes<'a, 'tcx> { + cx: &'a LateContext<'a, 'tcx>, ty: Option>, }; - impl<'tcx> ty::fold::TypeVisitor<'tcx> for ProhibitOpaqueTypes<'tcx> { + impl<'a, 'tcx> ty::fold::TypeVisitor<'tcx> for ProhibitOpaqueTypes<'a, 'tcx> { fn visit_ty(&mut self, ty: Ty<'tcx>) -> bool { - if let ty::Opaque(..) = ty.kind { - self.ty = Some(ty); - true - } else { - ty.super_visit_with(self) + match ty.kind { + ty::Opaque(..) => { + self.ty = Some(ty); + true + } + // Consider opaque types within projections FFI-safe if they do not normalize + // to more opaque types. + ty::Projection(..) => { + let ty = self.cx.tcx.normalize_erasing_regions(self.cx.param_env, ty); + + // If `ty` is a opaque type directly then `super_visit_with` won't invoke + // this function again. + if ty.has_opaque_types() { self.visit_ty(ty) } else { false } + } + _ => ty.super_visit_with(self), } } } - let mut visitor = ProhibitOpaqueTypes { ty: None }; + let mut visitor = ProhibitOpaqueTypes { cx: self.cx, ty: None }; ty.visit_with(&mut visitor); if let Some(ty) = visitor.ty { self.emit_ffi_unsafe_type_lint(ty, sp, "opaque types have no C equivalent", None); diff --git a/src/librustc_middle/hir/map/collector.rs b/src/librustc_middle/hir/map/collector.rs index 2906da437abac..dce06a5f7eeec 100644 --- a/src/librustc_middle/hir/map/collector.rs +++ b/src/librustc_middle/hir/map/collector.rs @@ -117,6 +117,7 @@ impl<'a, 'hir> NodeCollector<'a, 'hir> { body_ids: _, modules: _, proc_macros: _, + trait_map: _, } = *krate; hash_body(&mut hcx, root_mod_def_path_hash, item, &mut hir_body_nodes) @@ -241,11 +242,8 @@ impl<'a, 'hir> NodeCollector<'a, 'hir> { // Make sure that the DepNode of some node coincides with the HirId // owner of that node. if cfg!(debug_assertions) { - let node_id = self.definitions.hir_id_to_node_id(hir_id); - assert_eq!(self.definitions.node_id_to_hir_id(node_id), hir_id); - if hir_id.owner != self.current_dep_node_owner { - let node_str = match self.definitions.opt_local_def_id(node_id) { + let node_str = match self.definitions.opt_hir_id_to_local_def_id(hir_id) { Some(def_id) => self.definitions.def_path(def_id).to_string_no_crate(), None => format!("{:?}", node), }; @@ -335,9 +333,7 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> { debug!("visit_item: {:?}", i); debug_assert_eq!( i.hir_id.owner, - self.definitions - .opt_local_def_id(self.definitions.hir_id_to_node_id(i.hir_id)) - .unwrap() + self.definitions.opt_hir_id_to_local_def_id(i.hir_id).unwrap() ); self.with_dep_node_owner(i.hir_id.owner, i, |this, hash| { this.insert_with_hash(i.span, i.hir_id, Node::Item(i), hash); @@ -369,9 +365,7 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> { fn visit_trait_item(&mut self, ti: &'hir TraitItem<'hir>) { debug_assert_eq!( ti.hir_id.owner, - self.definitions - .opt_local_def_id(self.definitions.hir_id_to_node_id(ti.hir_id)) - .unwrap() + self.definitions.opt_hir_id_to_local_def_id(ti.hir_id).unwrap() ); self.with_dep_node_owner(ti.hir_id.owner, ti, |this, hash| { this.insert_with_hash(ti.span, ti.hir_id, Node::TraitItem(ti), hash); @@ -385,9 +379,7 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> { fn visit_impl_item(&mut self, ii: &'hir ImplItem<'hir>) { debug_assert_eq!( ii.hir_id.owner, - self.definitions - .opt_local_def_id(self.definitions.hir_id_to_node_id(ii.hir_id)) - .unwrap() + self.definitions.opt_hir_id_to_local_def_id(ii.hir_id).unwrap() ); self.with_dep_node_owner(ii.hir_id.owner, ii, |this, hash| { this.insert_with_hash(ii.span, ii.hir_id, Node::ImplItem(ii), hash); diff --git a/src/librustc_middle/lib.rs b/src/librustc_middle/lib.rs index 8025246f3d6f6..82dff60a26dcb 100644 --- a/src/librustc_middle/lib.rs +++ b/src/librustc_middle/lib.rs @@ -36,7 +36,6 @@ #![feature(drain_filter)] #![feature(never_type)] #![feature(exhaustive_patterns)] -#![feature(marker_trait_attr)] #![feature(extern_types)] #![feature(nll)] #![feature(option_expect_none)] diff --git a/src/librustc_middle/query/mod.rs b/src/librustc_middle/query/mod.rs index b3751beede25a..ca51d5b949c06 100644 --- a/src/librustc_middle/query/mod.rs +++ b/src/librustc_middle/query/mod.rs @@ -133,6 +133,23 @@ rustc_queries! { cache_on_disk_if { key.is_local() } } + /// Returns the list of predicates that can be used for + /// `SelectionCandidate::ProjectionCandidate` and + /// `ProjectionTyCandidate::TraitDef`. + /// Specifically this is the bounds (equivalent to) those + /// written on the trait's type definition, or those + /// after the `impl` keyword + /// + /// type X: Bound + 'lt + /// ^^^^^^^^^^^ + /// impl Debug + Display + /// ^^^^^^^^^^^^^^^ + /// + /// `key` is the `DefId` of the associated type or opaque type. + query projection_predicates(key: DefId) -> &'tcx ty::List> { + desc { |tcx| "finding projection predicates for `{}`", tcx.def_path_str(key) } + } + query native_libraries(_: CrateNum) -> Lrc> { desc { "looking up the native libraries of a linked crate" } } diff --git a/src/librustc_middle/ty/context.rs b/src/librustc_middle/ty/context.rs index 6380f8be98d13..5b44ffe8cafd7 100644 --- a/src/librustc_middle/ty/context.rs +++ b/src/librustc_middle/ty/context.rs @@ -1101,9 +1101,9 @@ impl<'tcx> TyCtxt<'tcx> { }; let mut trait_map: FxHashMap<_, FxHashMap<_, _>> = FxHashMap::default(); - for (hir_id, v) in resolutions.trait_map.into_iter() { + for (hir_id, v) in krate.trait_map.iter() { let map = trait_map.entry(hir_id.owner).or_default(); - map.insert(hir_id.local_id, StableVec::new(v)); + map.insert(hir_id.local_id, StableVec::new(v.to_vec())); } GlobalCtxt { diff --git a/src/librustc_middle/ty/flags.rs b/src/librustc_middle/ty/flags.rs index bee42be8a5388..d13be4f428534 100644 --- a/src/librustc_middle/ty/flags.rs +++ b/src/librustc_middle/ty/flags.rs @@ -93,7 +93,6 @@ impl FlagComputation { &ty::Bound(debruijn, _) => { self.add_binder(debruijn); - self.add_flags(TypeFlags::STILL_FURTHER_SPECIALIZABLE); } &ty::Placeholder(..) => { @@ -216,7 +215,6 @@ impl FlagComputation { } ty::ConstKind::Bound(debruijn, _) => { self.add_binder(debruijn); - self.add_flags(TypeFlags::STILL_FURTHER_SPECIALIZABLE); } ty::ConstKind::Param(_) => { self.add_flags(TypeFlags::HAS_CT_PARAM); diff --git a/src/librustc_middle/ty/mod.rs b/src/librustc_middle/ty/mod.rs index ca0a1ac71c644..56fb3b58d3f6b 100644 --- a/src/librustc_middle/ty/mod.rs +++ b/src/librustc_middle/ty/mod.rs @@ -121,7 +121,6 @@ pub struct ResolverOutputs { pub definitions: rustc_hir::definitions::Definitions, pub cstore: Box, pub extern_crate_map: FxHashMap, - pub trait_map: FxHashMap>, pub maybe_unused_trait_imports: FxHashSet, pub maybe_unused_extern_crates: Vec<(LocalDefId, Span)>, pub export_map: ExportMap, diff --git a/src/librustc_middle/ty/sty.rs b/src/librustc_middle/ty/sty.rs index b0addcb2bb683..1d680c3563675 100644 --- a/src/librustc_middle/ty/sty.rs +++ b/src/librustc_middle/ty/sty.rs @@ -1589,19 +1589,16 @@ impl RegionKind { flags = flags | TypeFlags::HAS_FREE_REGIONS; flags = flags | TypeFlags::HAS_FREE_LOCAL_REGIONS; flags = flags | TypeFlags::HAS_RE_INFER; - flags = flags | TypeFlags::STILL_FURTHER_SPECIALIZABLE; } ty::RePlaceholder(..) => { flags = flags | TypeFlags::HAS_FREE_REGIONS; flags = flags | TypeFlags::HAS_FREE_LOCAL_REGIONS; flags = flags | TypeFlags::HAS_RE_PLACEHOLDER; - flags = flags | TypeFlags::STILL_FURTHER_SPECIALIZABLE; } ty::ReEarlyBound(..) => { flags = flags | TypeFlags::HAS_FREE_REGIONS; flags = flags | TypeFlags::HAS_FREE_LOCAL_REGIONS; flags = flags | TypeFlags::HAS_RE_PARAM; - flags = flags | TypeFlags::STILL_FURTHER_SPECIALIZABLE; } ty::ReFree { .. } => { flags = flags | TypeFlags::HAS_FREE_REGIONS; diff --git a/src/librustc_middle/ty/subst.rs b/src/librustc_middle/ty/subst.rs index 3b4254a18ea61..fd31adae499fe 100644 --- a/src/librustc_middle/ty/subst.rs +++ b/src/librustc_middle/ty/subst.rs @@ -333,6 +333,17 @@ impl<'a, 'tcx> InternalSubsts<'tcx> { /// in a different item, with `target_substs` as the base for /// the target impl/trait, with the source child-specific /// parameters (e.g., method parameters) on top of that base. + /// + /// For example given: + /// + /// trait X { fn f(); } + /// impl X for U { fn f() {} } + /// + /// * If `self` is `[Self, S, T]`: the identity substs of `f` in the trait. + /// * If `source_ancestor` is the def_id of the trait. + /// * If `target_substs` is `[U]`, the substs for the impl. + /// * Then we will return `[U, T]`, the subst for `f` in the impl that + /// are needed for it to match the trait. pub fn rebase_onto( &self, tcx: TyCtxt<'tcx>, diff --git a/src/librustc_resolve/late/lifetimes.rs b/src/librustc_resolve/late/lifetimes.rs index 5bbf8703f0b60..903eee672cf1f 100644 --- a/src/librustc_resolve/late/lifetimes.rs +++ b/src/librustc_resolve/late/lifetimes.rs @@ -883,7 +883,6 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { }) .collect(); if !lifetimes.is_empty() { - self.trait_ref_hack = true; let next_early_index = self.next_early_index(); let scope = Scope::Binder { lifetimes, @@ -895,9 +894,10 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { let result = self.with(scope, |old_scope, this| { this.check_lifetime_params(old_scope, &bound_generic_params); this.visit_ty(&bounded_ty); + this.trait_ref_hack = true; walk_list!(this, visit_param_bound, bounds); + this.trait_ref_hack = false; }); - self.trait_ref_hack = false; result } else { self.visit_ty(&bounded_ty); @@ -932,13 +932,15 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { debug!("visit_poly_trait_ref(trait_ref={:?})", trait_ref); let should_pop_missing_lt = self.is_trait_ref_fn_scope(trait_ref); - if !self.trait_ref_hack + + let trait_ref_hack = take(&mut self.trait_ref_hack); + if !trait_ref_hack || trait_ref.bound_generic_params.iter().any(|param| match param.kind { GenericParamKind::Lifetime { .. } => true, _ => false, }) { - if self.trait_ref_hack { + if trait_ref_hack { struct_span_err!( self.tcx.sess, trait_ref.span, @@ -968,10 +970,11 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { this.check_lifetime_params(old_scope, &trait_ref.bound_generic_params); walk_list!(this, visit_generic_param, trait_ref.bound_generic_params); this.visit_trait_ref(&trait_ref.trait_ref); - }) + }); } else { self.visit_trait_ref(&trait_ref.trait_ref); } + self.trait_ref_hack = trait_ref_hack; if should_pop_missing_lt { self.missing_named_lifetime_spots.pop(); } diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 66e5612b627b4..91bd155614178 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -1109,6 +1109,10 @@ impl rustc_ast_lowering::Resolver for Resolver<'_> { fn next_node_id(&mut self) -> NodeId { self.next_node_id() } + + fn trait_map(&self) -> &NodeMap> { + &self.trait_map + } } impl<'a> Resolver<'a> { @@ -1284,11 +1288,6 @@ impl<'a> Resolver<'a> { let definitions = self.definitions; let extern_crate_map = self.extern_crate_map; let export_map = self.export_map; - let trait_map = self - .trait_map - .into_iter() - .map(|(k, v)| (definitions.node_id_to_hir_id(k), v)) - .collect(); let maybe_unused_trait_imports = self.maybe_unused_trait_imports; let maybe_unused_extern_crates = self.maybe_unused_extern_crates; let glob_map = self.glob_map; @@ -1297,7 +1296,6 @@ impl<'a> Resolver<'a> { cstore: Box::new(self.crate_loader.into_cstore()), extern_crate_map, export_map, - trait_map, glob_map, maybe_unused_trait_imports, maybe_unused_extern_crates, @@ -1315,11 +1313,6 @@ impl<'a> Resolver<'a> { cstore: Box::new(self.cstore().clone()), extern_crate_map: self.extern_crate_map.clone(), export_map: self.export_map.clone(), - trait_map: self - .trait_map - .iter() - .map(|(&k, v)| (self.definitions.node_id_to_hir_id(k), v.clone())) - .collect(), glob_map: self.glob_map.clone(), maybe_unused_trait_imports: self.maybe_unused_trait_imports.clone(), maybe_unused_extern_crates: self.maybe_unused_extern_crates.clone(), diff --git a/src/librustc_trait_selection/autoderef.rs b/src/librustc_trait_selection/autoderef.rs new file mode 100644 index 0000000000000..d542e16d83f10 --- /dev/null +++ b/src/librustc_trait_selection/autoderef.rs @@ -0,0 +1,229 @@ +use crate::traits::query::evaluate_obligation::InferCtxtExt; +use crate::traits::{self, TraitEngine}; +use rustc_errors::struct_span_err; +use rustc_hir as hir; +use rustc_infer::infer::InferCtxt; +use rustc_middle::ty::{self, TraitRef, Ty, TyCtxt, WithConstness}; +use rustc_middle::ty::{ToPredicate, TypeFoldable}; +use rustc_session::DiagnosticMessageId; +use rustc_span::symbol::Ident; +use rustc_span::Span; + +#[derive(Copy, Clone, Debug)] +pub enum AutoderefKind { + Builtin, + Overloaded, +} + +struct AutoderefSnapshot<'tcx> { + at_start: bool, + reached_recursion_limit: bool, + steps: Vec<(Ty<'tcx>, AutoderefKind)>, + cur_ty: Ty<'tcx>, + obligations: Vec>, +} + +pub struct Autoderef<'a, 'tcx> { + // Meta infos: + infcx: &'a InferCtxt<'a, 'tcx>, + span: Span, + body_id: hir::HirId, + param_env: ty::ParamEnv<'tcx>, + + // Current state: + state: AutoderefSnapshot<'tcx>, + + // Configurations: + include_raw_pointers: bool, + silence_errors: bool, +} + +impl<'a, 'tcx> Iterator for Autoderef<'a, 'tcx> { + type Item = (Ty<'tcx>, usize); + + fn next(&mut self) -> Option { + let tcx = self.infcx.tcx; + + debug!("autoderef: steps={:?}, cur_ty={:?}", self.state.steps, self.state.cur_ty); + if self.state.at_start { + self.state.at_start = false; + debug!("autoderef stage #0 is {:?}", self.state.cur_ty); + return Some((self.state.cur_ty, 0)); + } + + // If we have reached the recursion limit, error gracefully. + if !tcx.sess.recursion_limit().value_within_limit(self.state.steps.len()) { + if !self.silence_errors { + report_autoderef_recursion_limit_error(tcx, self.span, self.state.cur_ty); + } + self.state.reached_recursion_limit = true; + return None; + } + + if self.state.cur_ty.is_ty_var() { + return None; + } + + // Otherwise, deref if type is derefable: + let (kind, new_ty) = + if let Some(mt) = self.state.cur_ty.builtin_deref(self.include_raw_pointers) { + (AutoderefKind::Builtin, mt.ty) + } else if let Some(ty) = self.overloaded_deref_ty(self.state.cur_ty) { + (AutoderefKind::Overloaded, ty) + } else { + return None; + }; + + if new_ty.references_error() { + return None; + } + + self.state.steps.push((self.state.cur_ty, kind)); + debug!( + "autoderef stage #{:?} is {:?} from {:?}", + self.step_count(), + new_ty, + (self.state.cur_ty, kind) + ); + self.state.cur_ty = new_ty; + + Some((self.state.cur_ty, self.step_count())) + } +} + +impl<'a, 'tcx> Autoderef<'a, 'tcx> { + pub fn new( + infcx: &'a InferCtxt<'a, 'tcx>, + param_env: ty::ParamEnv<'tcx>, + body_id: hir::HirId, + span: Span, + base_ty: Ty<'tcx>, + ) -> Autoderef<'a, 'tcx> { + Autoderef { + infcx, + span, + body_id, + param_env, + state: AutoderefSnapshot { + steps: vec![], + cur_ty: infcx.resolve_vars_if_possible(&base_ty), + obligations: vec![], + at_start: true, + reached_recursion_limit: false, + }, + include_raw_pointers: false, + silence_errors: false, + } + } + + fn overloaded_deref_ty(&mut self, ty: Ty<'tcx>) -> Option> { + debug!("overloaded_deref_ty({:?})", ty); + + let tcx = self.infcx.tcx; + + // + let trait_ref = TraitRef { + def_id: tcx.lang_items().deref_trait()?, + substs: tcx.mk_substs_trait(ty, &[]), + }; + + let cause = traits::ObligationCause::misc(self.span, self.body_id); + + let obligation = traits::Obligation::new( + cause.clone(), + self.param_env, + trait_ref.without_const().to_predicate(tcx), + ); + if !self.infcx.predicate_may_hold(&obligation) { + debug!("overloaded_deref_ty: cannot match obligation"); + return None; + } + + let mut fulfillcx = traits::FulfillmentContext::new_in_snapshot(); + let normalized_ty = fulfillcx.normalize_projection_type( + &self.infcx, + self.param_env, + ty::ProjectionTy::from_ref_and_name(tcx, trait_ref, Ident::from_str("Target")), + cause, + ); + if let Err(e) = fulfillcx.select_where_possible(&self.infcx) { + // This shouldn't happen, except for evaluate/fulfill mismatches, + // but that's not a reason for an ICE (`predicate_may_hold` is conservative + // by design). + debug!("overloaded_deref_ty: encountered errors {:?} while fulfilling", e); + return None; + } + let obligations = fulfillcx.pending_obligations(); + debug!("overloaded_deref_ty({:?}) = ({:?}, {:?})", ty, normalized_ty, obligations); + self.state.obligations.extend(obligations); + + Some(self.infcx.resolve_vars_if_possible(&normalized_ty)) + } + + /// Returns the final type we ended up with, which may be an inference + /// variable (we will resolve it first, if we want). + pub fn final_ty(&self, resolve: bool) -> Ty<'tcx> { + if resolve { + self.infcx.resolve_vars_if_possible(&self.state.cur_ty) + } else { + self.state.cur_ty + } + } + + pub fn step_count(&self) -> usize { + self.state.steps.len() + } + + pub fn into_obligations(self) -> Vec> { + self.state.obligations + } + + pub fn steps(&self) -> &[(Ty<'tcx>, AutoderefKind)] { + &self.state.steps + } + + pub fn span(&self) -> Span { + self.span.clone() + } + + pub fn reached_recursion_limit(&self) -> bool { + self.state.reached_recursion_limit + } + + /// also dereference through raw pointer types + /// e.g., assuming ptr_to_Foo is the type `*const Foo` + /// fcx.autoderef(span, ptr_to_Foo) => [*const Foo] + /// fcx.autoderef(span, ptr_to_Foo).include_raw_ptrs() => [*const Foo, Foo] + pub fn include_raw_pointers(mut self) -> Self { + self.include_raw_pointers = true; + self + } + + pub fn silence_errors(mut self) -> Self { + self.silence_errors = true; + self + } +} + +pub fn report_autoderef_recursion_limit_error<'tcx>(tcx: TyCtxt<'tcx>, span: Span, ty: Ty<'tcx>) { + // We've reached the recursion limit, error gracefully. + let suggested_limit = tcx.sess.recursion_limit() * 2; + let msg = format!("reached the recursion limit while auto-dereferencing `{:?}`", ty); + let error_id = (DiagnosticMessageId::ErrorId(55), Some(span), msg); + let fresh = tcx.sess.one_time_diagnostics.borrow_mut().insert(error_id); + if fresh { + struct_span_err!( + tcx.sess, + span, + E0055, + "reached the recursion limit while auto-dereferencing `{:?}`", + ty + ) + .span_label(span, "deref recursion limit reached") + .help(&format!( + "consider adding a `#![recursion_limit=\"{}\"]` attribute to your crate (`{}`)", + suggested_limit, tcx.crate_name, + )) + .emit(); + } +} diff --git a/src/librustc_trait_selection/lib.rs b/src/librustc_trait_selection/lib.rs index ea886cd1f9e9b..4692fa04ed587 100644 --- a/src/librustc_trait_selection/lib.rs +++ b/src/librustc_trait_selection/lib.rs @@ -28,6 +28,7 @@ extern crate log; #[macro_use] extern crate rustc_middle; +pub mod autoderef; pub mod infer; pub mod opaque_types; pub mod traits; diff --git a/src/librustc_trait_selection/traits/error_reporting/mod.rs b/src/librustc_trait_selection/traits/error_reporting/mod.rs index 060877f80adef..fd0c1a54d27ad 100644 --- a/src/librustc_trait_selection/traits/error_reporting/mod.rs +++ b/src/librustc_trait_selection/traits/error_reporting/mod.rs @@ -402,6 +402,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { err.span_label(enclosing_scope_span, s.as_str()); } + self.suggest_dereferences(&obligation, &mut err, &trait_ref, points_at_arg); self.suggest_borrow_on_unsized_slice(&obligation.cause.code, &mut err); self.suggest_fn_call(&obligation, &mut err, &trait_ref, points_at_arg); self.suggest_remove_reference(&obligation, &mut err, &trait_ref); diff --git a/src/librustc_trait_selection/traits/error_reporting/suggestions.rs b/src/librustc_trait_selection/traits/error_reporting/suggestions.rs index dfd7dac72d8e1..176bd90303ddd 100644 --- a/src/librustc_trait_selection/traits/error_reporting/suggestions.rs +++ b/src/librustc_trait_selection/traits/error_reporting/suggestions.rs @@ -3,6 +3,7 @@ use super::{ SelectionContext, }; +use crate::autoderef::Autoderef; use crate::infer::InferCtxt; use crate::traits::normalize_projection_type; @@ -13,11 +14,11 @@ use rustc_hir::def_id::DefId; use rustc_hir::intravisit::Visitor; use rustc_hir::lang_items; use rustc_hir::{AsyncGeneratorKind, GeneratorKind, Node}; -use rustc_middle::ty::TypeckTables; use rustc_middle::ty::{ self, suggest_constraining_type_param, AdtKind, DefIdTree, Infer, InferTy, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness, }; +use rustc_middle::ty::{TypeAndMut, TypeckTables}; use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::{MultiSpan, Span, DUMMY_SP}; use std::fmt; @@ -48,6 +49,14 @@ pub trait InferCtxtExt<'tcx> { err: &mut DiagnosticBuilder<'_>, ); + fn suggest_dereferences( + &self, + obligation: &PredicateObligation<'tcx>, + err: &mut DiagnosticBuilder<'tcx>, + trait_ref: &ty::PolyTraitRef<'tcx>, + points_at_arg: bool, + ); + fn get_closure_name( &self, def_id: DefId, @@ -450,6 +459,62 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { } } + /// When after several dereferencing, the reference satisfies the trait + /// binding. This function provides dereference suggestion for this + /// specific situation. + fn suggest_dereferences( + &self, + obligation: &PredicateObligation<'tcx>, + err: &mut DiagnosticBuilder<'tcx>, + trait_ref: &ty::PolyTraitRef<'tcx>, + points_at_arg: bool, + ) { + // It only make sense when suggesting dereferences for arguments + if !points_at_arg { + return; + } + let param_env = obligation.param_env; + let body_id = obligation.cause.body_id; + let span = obligation.cause.span; + let real_trait_ref = match &obligation.cause.code { + ObligationCauseCode::ImplDerivedObligation(cause) + | ObligationCauseCode::DerivedObligation(cause) + | ObligationCauseCode::BuiltinDerivedObligation(cause) => &cause.parent_trait_ref, + _ => trait_ref, + }; + let real_ty = match real_trait_ref.self_ty().no_bound_vars() { + Some(ty) => ty, + None => return, + }; + + if let ty::Ref(region, base_ty, mutbl) = real_ty.kind { + let mut autoderef = Autoderef::new(self, param_env, body_id, span, base_ty); + if let Some(steps) = autoderef.find_map(|(ty, steps)| { + // Re-add the `&` + let ty = self.tcx.mk_ref(region, TypeAndMut { ty, mutbl }); + let obligation = + self.mk_trait_obligation_with_new_self_ty(param_env, real_trait_ref, ty); + Some(steps).filter(|_| self.predicate_may_hold(&obligation)) + }) { + if steps > 0 { + if let Ok(src) = self.tcx.sess.source_map().span_to_snippet(span) { + // Don't care about `&mut` because `DerefMut` is used less + // often and user will not expect autoderef happens. + if src.starts_with("&") && !src.starts_with("&mut ") { + let derefs = "*".repeat(steps); + err.span_suggestion( + span, + "consider adding dereference here", + format!("&{}{}", derefs, &src[1..]), + Applicability::MachineApplicable, + ); + } + } + } + } + } + } + /// When encountering an assignment of an unsized trait, like `let x = ""[..];`, provide a /// suggestion to borrow the initializer in order to use have a slice instead. fn suggest_borrow_on_unsized_slice( diff --git a/src/librustc_trait_selection/traits/project.rs b/src/librustc_trait_selection/traits/project.rs index 1964054254734..574d50a4fccc2 100644 --- a/src/librustc_trait_selection/traits/project.rs +++ b/src/librustc_trait_selection/traits/project.rs @@ -896,9 +896,12 @@ fn assemble_candidates_from_trait_def<'cx, 'tcx>( let tcx = selcx.tcx(); // Check whether the self-type is itself a projection. - let (def_id, substs) = match obligation_trait_ref.self_ty().kind { - ty::Projection(ref data) => (data.trait_ref(tcx).def_id, data.substs), - ty::Opaque(def_id, substs) => (def_id, substs), + // If so, extract what we know from the trait and try to come up with a good answer. + let bounds = match obligation_trait_ref.self_ty().kind { + ty::Projection(ref data) => { + tcx.projection_predicates(data.item_def_id).subst(tcx, data.substs) + } + ty::Opaque(def_id, substs) => tcx.projection_predicates(def_id).subst(tcx, substs), ty::Infer(ty::TyVar(_)) => { // If the self-type is an inference variable, then it MAY wind up // being a projected type, so induce an ambiguity. @@ -908,17 +911,13 @@ fn assemble_candidates_from_trait_def<'cx, 'tcx>( _ => return, }; - // If so, extract what we know from the trait and try to come up with a good answer. - let trait_predicates = tcx.predicates_of(def_id); - let bounds = trait_predicates.instantiate(tcx, substs); - let bounds = elaborate_predicates(tcx, bounds.predicates.into_iter()).map(|o| o.predicate); assemble_candidates_from_predicates( selcx, obligation, obligation_trait_ref, candidate_set, ProjectionTyCandidate::TraitDef, - bounds, + bounds.iter(), ) } @@ -1484,6 +1483,12 @@ fn confirm_impl_candidate<'cx, 'tcx>( ); return Progress { ty: tcx.ty_error(), obligations: nested }; } + // If we're trying to normalize ` as X>::A` using + //`impl X for Vec { type A = Box; }`, then: + // + // * `obligation.predicate.substs` is `[Vec, S]` + // * `substs` is `[u32]` + // * `substs` ends up as `[u32, S]` let substs = obligation.predicate.substs.rebase_onto(tcx, trait_def_id, substs); let substs = translate_substs(selcx.infcx(), param_env, impl_def_id, substs, assoc_ty.defining_node); diff --git a/src/librustc_trait_selection/traits/select/mod.rs b/src/librustc_trait_selection/traits/select/mod.rs index 7dc8c2cf4cdc2..076bdad423ab8 100644 --- a/src/librustc_trait_selection/traits/select/mod.rs +++ b/src/librustc_trait_selection/traits/select/mod.rs @@ -1273,9 +1273,12 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { placeholder_trait_predicate, ); - let (def_id, substs) = match placeholder_trait_predicate.trait_ref.self_ty().kind { - ty::Projection(ref data) => (data.trait_ref(self.tcx()).def_id, data.substs), - ty::Opaque(def_id, substs) => (def_id, substs), + let tcx = self.infcx.tcx; + let predicates = match placeholder_trait_predicate.trait_ref.self_ty().kind { + ty::Projection(ref data) => { + tcx.projection_predicates(data.item_def_id).subst(tcx, data.substs) + } + ty::Opaque(def_id, substs) => tcx.projection_predicates(def_id).subst(tcx, substs), _ => { span_bug!( obligation.cause.span, @@ -1285,32 +1288,23 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ); } }; - debug!( - "match_projection_obligation_against_definition_bounds: \ - def_id={:?}, substs={:?}", - def_id, substs - ); - let predicates_of = self.tcx().predicates_of(def_id); - let bounds = predicates_of.instantiate(self.tcx(), substs); - debug!( - "match_projection_obligation_against_definition_bounds: \ - bounds={:?}", - bounds - ); - - let elaborated_predicates = - util::elaborate_predicates(self.tcx(), bounds.predicates.into_iter()); - let matching_bound = elaborated_predicates.filter_to_traits().find(|bound| { - self.infcx.probe(|_| { - self.match_projection( - obligation, - *bound, - placeholder_trait_predicate.trait_ref, - &placeholder_map, - snapshot, - ) - }) + let matching_bound = predicates.iter().find_map(|bound| { + if let ty::PredicateKind::Trait(bound, _) = bound.kind() { + let bound = bound.to_poly_trait_ref(); + if self.infcx.probe(|_| { + self.match_projection( + obligation, + bound, + placeholder_trait_predicate.trait_ref, + &placeholder_map, + snapshot, + ) + }) { + return Some(bound); + } + } + None }); debug!( diff --git a/src/librustc_ty/ty.rs b/src/librustc_ty/ty.rs index cf70a845af0aa..595992d01dd2d 100644 --- a/src/librustc_ty/ty.rs +++ b/src/librustc_ty/ty.rs @@ -1,8 +1,10 @@ use rustc_data_structures::svh::Svh; use rustc_hir as hir; +use rustc_hir::def::DefKind; use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, LOCAL_CRATE}; +use rustc_infer::traits::util; use rustc_middle::hir::map as hir_map; -use rustc_middle::ty::subst::Subst; +use rustc_middle::ty::subst::{InternalSubsts, Subst}; use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt, WithConstness}; use rustc_session::CrateDisambiguator; use rustc_span::symbol::Symbol; @@ -365,6 +367,133 @@ fn asyncness(tcx: TyCtxt<'_>, def_id: DefId) -> hir::IsAsync { fn_like.asyncness() } +/// For associated types we allow bounds written on the associated type +/// (`type X: Trait`) to be used as candidates. We also allow the same bounds +/// when desugared as bounds on the trait `where Self::X: Trait`. +/// +/// Note that this filtering is done with the items identity substs to +/// simplify checking that these bounds are met in impls. This means that +/// a bound such as `for<'b> >::U: Clone` can't be used, as in +/// `hr-associated-type-bound-1.rs`. +fn associated_type_projection_predicates( + tcx: TyCtxt<'_>, + assoc_item_def_id: DefId, +) -> &'_ ty::List> { + let generic_trait_bounds = tcx.predicates_of(assoc_item_def_id); + // We include predicates from the trait as well to handle + // `where Self::X: Trait`. + let item_bounds = generic_trait_bounds.instantiate_identity(tcx); + let item_predicates = util::elaborate_predicates(tcx, item_bounds.predicates.into_iter()); + + let assoc_item_ty = ty::ProjectionTy { + item_def_id: assoc_item_def_id, + substs: InternalSubsts::identity_for_item(tcx, assoc_item_def_id), + }; + + let predicates = item_predicates.filter_map(|obligation| { + let pred = obligation.predicate; + match pred.kind() { + ty::PredicateKind::Trait(tr, _) => { + if let ty::Projection(p) = tr.skip_binder().self_ty().kind { + if p == assoc_item_ty { + return Some(pred); + } + } + } + ty::PredicateKind::Projection(proj) => { + if let ty::Projection(p) = proj.skip_binder().projection_ty.self_ty().kind { + if p == assoc_item_ty { + return Some(pred); + } + } + } + ty::PredicateKind::TypeOutlives(outlives) => { + if let ty::Projection(p) = outlives.skip_binder().0.kind { + if p == assoc_item_ty { + return Some(pred); + } + } + } + _ => {} + } + None + }); + + let result = tcx.mk_predicates(predicates); + debug!( + "associated_type_projection_predicates({}) = {:?}", + tcx.def_path_str(assoc_item_def_id), + result + ); + result +} + +/// Opaque types don't have the same issues as associated types: the only +/// predicates on an opaque type (excluding those it inherits from its parent +/// item) should be of the form we're expecting. +fn opaque_type_projection_predicates( + tcx: TyCtxt<'_>, + def_id: DefId, +) -> &'_ ty::List> { + let substs = InternalSubsts::identity_for_item(tcx, def_id); + + let bounds = tcx.predicates_of(def_id); + let predicates = + util::elaborate_predicates(tcx, bounds.predicates.into_iter().map(|&(pred, _)| pred)); + + let filtered_predicates = predicates.filter_map(|obligation| { + let pred = obligation.predicate; + match pred.kind() { + ty::PredicateKind::Trait(tr, _) => { + if let ty::Opaque(opaque_def_id, opaque_substs) = tr.skip_binder().self_ty().kind { + if opaque_def_id == def_id && opaque_substs == substs { + return Some(pred); + } + } + } + ty::PredicateKind::Projection(proj) => { + if let ty::Opaque(opaque_def_id, opaque_substs) = + proj.skip_binder().projection_ty.self_ty().kind + { + if opaque_def_id == def_id && opaque_substs == substs { + return Some(pred); + } + } + } + ty::PredicateKind::TypeOutlives(outlives) => { + if let ty::Opaque(opaque_def_id, opaque_substs) = outlives.skip_binder().0.kind { + if opaque_def_id == def_id && opaque_substs == substs { + return Some(pred); + } + } else { + // These can come from elaborating other predicates + return None; + } + } + // These can come from elaborating other predicates + ty::PredicateKind::RegionOutlives(_) => return None, + _ => {} + } + tcx.sess.delay_span_bug( + obligation.cause.span(tcx), + &format!("unexpected predicate {:?} on opaque type", pred), + ); + None + }); + + let result = tcx.mk_predicates(filtered_predicates); + debug!("opaque_type_projection_predicates({}) = {:?}", tcx.def_path_str(def_id), result); + result +} + +fn projection_predicates(tcx: TyCtxt<'_>, def_id: DefId) -> &'_ ty::List> { + match tcx.def_kind(def_id) { + DefKind::AssocTy => associated_type_projection_predicates(tcx, def_id), + DefKind::OpaqueTy => opaque_type_projection_predicates(tcx, def_id), + k => bug!("projection_predicates called on {}", k.descr(def_id)), + } +} + pub fn provide(providers: &mut ty::query::Providers<'_>) { *providers = ty::query::Providers { asyncness, @@ -381,6 +510,7 @@ pub fn provide(providers: &mut ty::query::Providers<'_>) { instance_def_size_estimate, issue33140_self_ty, impl_defaultness, + projection_predicates, ..*providers }; } diff --git a/src/librustc_typeck/check/autoderef.rs b/src/librustc_typeck/check/autoderef.rs index 2570025959cb4..97d2b3e5a8e45 100644 --- a/src/librustc_typeck/check/autoderef.rs +++ b/src/librustc_typeck/check/autoderef.rs @@ -1,191 +1,46 @@ +//! Some helper functions for `AutoDeref` use super::method::MethodCallee; use super::{FnCtxt, PlaceOp}; -use rustc_errors::struct_span_err; -use rustc_hir as hir; -use rustc_infer::infer::{InferCtxt, InferOk}; +use rustc_infer::infer::InferOk; use rustc_middle::ty::adjustment::{Adjust, Adjustment, OverloadedDeref}; -use rustc_middle::ty::{self, TraitRef, Ty, TyCtxt, WithConstness}; -use rustc_middle::ty::{ToPredicate, TypeFoldable}; -use rustc_session::DiagnosticMessageId; -use rustc_span::symbol::Ident; +use rustc_middle::ty::{self, Ty}; use rustc_span::Span; -use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt; -use rustc_trait_selection::traits::{self, TraitEngine}; +use rustc_trait_selection::autoderef::{Autoderef, AutoderefKind}; use std::iter; -#[derive(Copy, Clone, Debug)] -enum AutoderefKind { - Builtin, - Overloaded, -} - -pub struct Autoderef<'a, 'tcx> { - infcx: &'a InferCtxt<'a, 'tcx>, - body_id: hir::HirId, - param_env: ty::ParamEnv<'tcx>, - steps: Vec<(Ty<'tcx>, AutoderefKind)>, - cur_ty: Ty<'tcx>, - obligations: Vec>, - at_start: bool, - include_raw_pointers: bool, - span: Span, - silence_errors: bool, - reached_recursion_limit: bool, -} - -impl<'a, 'tcx> Iterator for Autoderef<'a, 'tcx> { - type Item = (Ty<'tcx>, usize); - - fn next(&mut self) -> Option { - let tcx = self.infcx.tcx; - - debug!("autoderef: steps={:?}, cur_ty={:?}", self.steps, self.cur_ty); - if self.at_start { - self.at_start = false; - debug!("autoderef stage #0 is {:?}", self.cur_ty); - return Some((self.cur_ty, 0)); - } - - if !tcx.sess.recursion_limit().value_within_limit(self.steps.len()) { - if !self.silence_errors { - report_autoderef_recursion_limit_error(tcx, self.span, self.cur_ty); - } - self.reached_recursion_limit = true; - return None; - } - - if self.cur_ty.is_ty_var() { - return None; - } - - // Otherwise, deref if type is derefable: - let (kind, new_ty) = if let Some(mt) = self.cur_ty.builtin_deref(self.include_raw_pointers) - { - (AutoderefKind::Builtin, mt.ty) - } else { - let ty = self.overloaded_deref_ty(self.cur_ty)?; - (AutoderefKind::Overloaded, ty) - }; - - if new_ty.references_error() { - return None; - } - - self.steps.push((self.cur_ty, kind)); - debug!( - "autoderef stage #{:?} is {:?} from {:?}", - self.steps.len(), - new_ty, - (self.cur_ty, kind) - ); - self.cur_ty = new_ty; - - Some((self.cur_ty, self.steps.len())) +impl<'a, 'tcx> FnCtxt<'a, 'tcx> { + pub fn autoderef(&'a self, span: Span, base_ty: Ty<'tcx>) -> Autoderef<'a, 'tcx> { + Autoderef::new(self, self.param_env, self.body_id, span, base_ty) } -} -impl<'a, 'tcx> Autoderef<'a, 'tcx> { - pub fn new( - infcx: &'a InferCtxt<'a, 'tcx>, - param_env: ty::ParamEnv<'tcx>, - body_id: hir::HirId, + pub fn try_overloaded_deref( + &self, span: Span, base_ty: Ty<'tcx>, - ) -> Autoderef<'a, 'tcx> { - Autoderef { - infcx, - body_id, - param_env, - steps: vec![], - cur_ty: infcx.resolve_vars_if_possible(&base_ty), - obligations: vec![], - at_start: true, - include_raw_pointers: false, - silence_errors: false, - reached_recursion_limit: false, - span, - } - } - - fn overloaded_deref_ty(&mut self, ty: Ty<'tcx>) -> Option> { - debug!("overloaded_deref_ty({:?})", ty); - - let tcx = self.infcx.tcx; - - // - let trait_ref = TraitRef { - def_id: tcx.lang_items().deref_trait()?, - substs: tcx.mk_substs_trait(ty, &[]), - }; - - let cause = traits::ObligationCause::misc(self.span, self.body_id); - - let obligation = traits::Obligation::new( - cause.clone(), - self.param_env, - trait_ref.without_const().to_predicate(tcx), - ); - if !self.infcx.predicate_may_hold(&obligation) { - debug!("overloaded_deref_ty: cannot match obligation"); - return None; - } - - let mut fulfillcx = traits::FulfillmentContext::new_in_snapshot(); - let normalized_ty = fulfillcx.normalize_projection_type( - &self.infcx, - self.param_env, - ty::ProjectionTy::from_ref_and_name(tcx, trait_ref, Ident::from_str("Target")), - cause, - ); - if let Err(e) = fulfillcx.select_where_possible(&self.infcx) { - // This shouldn't happen, except for evaluate/fulfill mismatches, - // but that's not a reason for an ICE (`predicate_may_hold` is conservative - // by design). - debug!("overloaded_deref_ty: encountered errors {:?} while fulfilling", e); - return None; - } - let obligations = fulfillcx.pending_obligations(); - debug!("overloaded_deref_ty({:?}) = ({:?}, {:?})", ty, normalized_ty, obligations); - self.obligations.extend(obligations); - - Some(self.infcx.resolve_vars_if_possible(&normalized_ty)) - } - - /// Returns the final type, generating an error if it is an - /// unresolved inference variable. - pub fn unambiguous_final_ty(&self, fcx: &FnCtxt<'a, 'tcx>) -> Ty<'tcx> { - fcx.structurally_resolved_type(self.span, self.cur_ty) - } - - /// Returns the final type we ended up with, which may well be an - /// inference variable (we will resolve it first, if possible). - pub fn maybe_ambiguous_final_ty(&self) -> Ty<'tcx> { - self.infcx.resolve_vars_if_possible(&self.cur_ty) - } - - pub fn step_count(&self) -> usize { - self.steps.len() + ) -> Option>> { + self.try_overloaded_place_op(span, base_ty, &[], PlaceOp::Deref) } /// Returns the adjustment steps. - pub fn adjust_steps(&self, fcx: &FnCtxt<'a, 'tcx>) -> Vec> { - fcx.register_infer_ok_obligations(self.adjust_steps_as_infer_ok(fcx)) + pub fn adjust_steps(&self, autoderef: &Autoderef<'a, 'tcx>) -> Vec> { + self.register_infer_ok_obligations(self.adjust_steps_as_infer_ok(autoderef)) } pub fn adjust_steps_as_infer_ok( &self, - fcx: &FnCtxt<'a, 'tcx>, + autoderef: &Autoderef<'a, 'tcx>, ) -> InferOk<'tcx, Vec>> { let mut obligations = vec![]; - let targets = self.steps.iter().skip(1).map(|&(ty, _)| ty).chain(iter::once(self.cur_ty)); - let steps: Vec<_> = self - .steps + let steps = autoderef.steps(); + let targets = + steps.iter().skip(1).map(|&(ty, _)| ty).chain(iter::once(autoderef.final_ty(false))); + let steps: Vec<_> = steps .iter() .map(|&(source, kind)| { if let AutoderefKind::Overloaded = kind { - fcx.try_overloaded_deref(self.span, source).and_then( + self.try_overloaded_deref(autoderef.span(), source).and_then( |InferOk { value: method, obligations: o }| { obligations.extend(o); if let ty::Ref(region, _, mutbl) = method.sig.output().kind { @@ -205,67 +60,4 @@ impl<'a, 'tcx> Autoderef<'a, 'tcx> { InferOk { obligations, value: steps } } - - /// also dereference through raw pointer types - /// e.g., assuming ptr_to_Foo is the type `*const Foo` - /// fcx.autoderef(span, ptr_to_Foo) => [*const Foo] - /// fcx.autoderef(span, ptr_to_Foo).include_raw_ptrs() => [*const Foo, Foo] - pub fn include_raw_pointers(mut self) -> Self { - self.include_raw_pointers = true; - self - } - - pub fn silence_errors(mut self) -> Self { - self.silence_errors = true; - self - } - - pub fn reached_recursion_limit(&self) -> bool { - self.reached_recursion_limit - } - - pub fn finalize(self, fcx: &FnCtxt<'a, 'tcx>) { - fcx.register_predicates(self.into_obligations()); - } - - pub fn into_obligations(self) -> Vec> { - self.obligations - } -} - -pub fn report_autoderef_recursion_limit_error<'tcx>(tcx: TyCtxt<'tcx>, span: Span, ty: Ty<'tcx>) { - // We've reached the recursion limit, error gracefully. - let suggested_limit = tcx.sess.recursion_limit() * 2; - let msg = format!("reached the recursion limit while auto-dereferencing `{:?}`", ty); - let error_id = (DiagnosticMessageId::ErrorId(55), Some(span), msg); - let fresh = tcx.sess.one_time_diagnostics.borrow_mut().insert(error_id); - if fresh { - struct_span_err!( - tcx.sess, - span, - E0055, - "reached the recursion limit while auto-dereferencing `{:?}`", - ty - ) - .span_label(span, "deref recursion limit reached") - .help(&format!( - "consider adding a `#![recursion_limit=\"{}\"]` attribute to your crate (`{}`)", - suggested_limit, tcx.crate_name, - )) - .emit(); - } -} - -impl<'a, 'tcx> FnCtxt<'a, 'tcx> { - pub fn autoderef(&'a self, span: Span, base_ty: Ty<'tcx>) -> Autoderef<'a, 'tcx> { - Autoderef::new(self, self.param_env, self.body_id, span, base_ty) - } - - pub fn try_overloaded_deref( - &self, - span: Span, - base_ty: Ty<'tcx>, - ) -> Option>> { - self.try_overloaded_place_op(span, base_ty, &[], PlaceOp::Deref) - } } diff --git a/src/librustc_typeck/check/callee.rs b/src/librustc_typeck/check/callee.rs index fe200a0ad2a1c..308ed5d840202 100644 --- a/src/librustc_typeck/check/callee.rs +++ b/src/librustc_typeck/check/callee.rs @@ -1,4 +1,3 @@ -use super::autoderef::Autoderef; use super::method::MethodCallee; use super::{Expectation, FnCtxt, TupleArgumentsFlag}; use crate::type_error_struct; @@ -17,6 +16,7 @@ use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable}; use rustc_span::symbol::Ident; use rustc_span::Span; use rustc_target::spec::abi; +use rustc_trait_selection::autoderef::Autoderef; /// Checks that it is legal to call methods of the trait corresponding /// to `trait_id` (this only cares about the trait, not the specific @@ -72,7 +72,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { while result.is_none() && autoderef.next().is_some() { result = self.try_overloaded_call_step(call_expr, callee_expr, arg_exprs, &autoderef); } - autoderef.finalize(self); + self.register_predicates(autoderef.into_obligations()); let output = match result { None => { @@ -106,7 +106,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { arg_exprs: &'tcx [hir::Expr<'tcx>], autoderef: &Autoderef<'a, 'tcx>, ) -> Option> { - let adjusted_ty = autoderef.unambiguous_final_ty(self); + let adjusted_ty = + self.structurally_resolved_type(autoderef.span(), autoderef.final_ty(false)); debug!( "try_overloaded_call_step(call_expr={:?}, adjusted_ty={:?})", call_expr, adjusted_ty @@ -115,7 +116,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // If the callee is a bare function or a closure, then we're all set. match adjusted_ty.kind { ty::FnDef(..) | ty::FnPtr(_) => { - let adjustments = autoderef.adjust_steps(self); + let adjustments = self.adjust_steps(autoderef); self.apply_adjustments(callee_expr, adjustments); return Some(CallStep::Builtin(adjusted_ty)); } @@ -135,7 +136,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { &closure_sig, ) .0; - let adjustments = autoderef.adjust_steps(self); + let adjustments = self.adjust_steps(autoderef); self.record_deferred_call_resolution( def_id, DeferredCallResolution { @@ -176,7 +177,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.try_overloaded_call_traits(call_expr, adjusted_ty, Some(arg_exprs)) .or_else(|| self.try_overloaded_call_traits(call_expr, adjusted_ty, None)) .map(|(autoref, method)| { - let mut adjustments = autoderef.adjust_steps(self); + let mut adjustments = self.adjust_steps(autoderef); adjustments.extend(autoref); self.apply_adjustments(callee_expr, adjustments); CallStep::Overloaded(method) diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs index 15d210b89b64d..dec53c369bb18 100644 --- a/src/librustc_typeck/check/coercion.rs +++ b/src/librustc_typeck/check/coercion.rs @@ -409,7 +409,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { } let InferOk { value: mut adjustments, obligations: o } = - autoderef.adjust_steps_as_infer_ok(self); + self.adjust_steps_as_infer_ok(&autoderef); obligations.extend(o); obligations.extend(autoderef.into_obligations()); diff --git a/src/librustc_typeck/check/compare_method.rs b/src/librustc_typeck/check/compare_method.rs index 1d47e64630c18..4e97ba41dcbb3 100644 --- a/src/librustc_typeck/check/compare_method.rs +++ b/src/librustc_typeck/check/compare_method.rs @@ -4,15 +4,17 @@ use rustc_hir::def::{DefKind, Res}; use rustc_hir::intravisit; use rustc_hir::{GenericParamKind, ImplItemKind, TraitItemKind}; use rustc_infer::infer::{self, InferOk, TyCtxtInferExt}; +use rustc_middle::ty; use rustc_middle::ty::error::{ExpectedFound, TypeError}; -use rustc_middle::ty::subst::{InternalSubsts, Subst}; +use rustc_middle::ty::subst::{InternalSubsts, Subst, SubstsRef}; use rustc_middle::ty::util::ExplicitSelf; -use rustc_middle::ty::{self, GenericParamDefKind, TyCtxt}; +use rustc_middle::ty::{GenericParamDefKind, ToPredicate, TyCtxt, WithConstness}; use rustc_span::Span; use rustc_trait_selection::traits::error_reporting::InferCtxtExt; use rustc_trait_selection::traits::{self, ObligationCause, ObligationCauseCode, Reveal}; use super::{potentially_plural_count, FnCtxt, Inherited}; +use std::iter; /// Checks that a method from an impl conforms to the signature of /// the same method as declared in the trait. @@ -1057,13 +1059,15 @@ crate fn compare_ty_impl<'tcx>( let _: Result<(), ErrorReported> = (|| { compare_number_of_generics(tcx, impl_ty, impl_ty_span, trait_ty, trait_item_span)?; - compare_type_predicate_entailment(tcx, impl_ty, impl_ty_span, trait_ty, impl_trait_ref) + compare_type_predicate_entailment(tcx, impl_ty, impl_ty_span, trait_ty, impl_trait_ref)?; + + compare_projection_bounds(tcx, trait_ty, impl_ty, impl_ty_span, impl_trait_ref) })(); } /// The equivalent of [compare_predicate_entailment], but for associated types /// instead of associated functions. -fn compare_type_predicate_entailment( +fn compare_type_predicate_entailment<'tcx>( tcx: TyCtxt<'tcx>, impl_ty: &ty::AssocItem, impl_ty_span: Span, @@ -1165,6 +1169,145 @@ fn compare_type_predicate_entailment( }) } +/// Validate that `ProjectionCandidate`s created for this associated type will +/// be valid. +/// +/// Usually given +/// +/// trait X { type Y: Copy } impl X for T { type Y = S; } +/// +/// We are able to normalize `::U` to `S`, and so when we check the +/// impl is well-formed we have to prove `S: Copy`. +/// +/// For default associated types the normalization is not possible (the value +/// from the impl could be overridden). We also can't normalize generic +/// associated types (yet) because they contain bound parameters. +fn compare_projection_bounds<'tcx>( + tcx: TyCtxt<'tcx>, + trait_ty: &ty::AssocItem, + impl_ty: &ty::AssocItem, + impl_ty_span: Span, + impl_trait_ref: ty::TraitRef<'tcx>, +) -> Result<(), ErrorReported> { + let have_gats = tcx.features().generic_associated_types; + if impl_ty.defaultness.is_final() && !have_gats { + // For "final", non-generic associate type implementations, we + // don't need this as described above. + return Ok(()); + } + + let param_env = tcx.param_env(impl_ty.def_id); + + // Given + // + // impl Foo for (A, B) { + // type Bar =... + // } + // + // - `impl_substs` would be `[A, B, C]` + // - `rebased_substs` would be `[(A, B), u32, C]`, combining the substs from + // the *trait* with the generic associated type parameters. + let impl_ty_substs = InternalSubsts::identity_for_item(tcx, impl_ty.def_id); + let rebased_substs = + impl_ty_substs.rebase_onto(tcx, impl_ty.container.id(), impl_trait_ref.substs); + let impl_ty_value = tcx.type_of(impl_ty.def_id); + + // Map the predicate from the trait to the corresponding one for the impl. + // For example: + // + // trait X { type Y<'a>: PartialEq } impl X for T { type Y<'a> = &'a S; } + // impl<'x> X<&'x u32> for () { type Y<'c> = &'c u32; } + // + // For the `for<'a> <>::Y<'a>: PartialEq` bound, this + // function would translate and partially normalize + // `[>::Y<'a>, A]` to `[&'a u32, &'x u32]`. + let translate_predicate_substs = move |predicate_substs: SubstsRef<'tcx>| { + tcx.mk_substs( + iter::once(impl_ty_value.into()) + .chain(predicate_substs[1..].iter().map(|s| s.subst(tcx, rebased_substs))), + ) + }; + + tcx.infer_ctxt().enter(move |infcx| { + let inh = Inherited::new(infcx, impl_ty.def_id.expect_local()); + let infcx = &inh.infcx; + let mut selcx = traits::SelectionContext::new(&infcx); + + let impl_ty_hir_id = tcx.hir().as_local_hir_id(impl_ty.def_id.expect_local()); + let normalize_cause = traits::ObligationCause::misc(impl_ty_span, impl_ty_hir_id); + let cause = ObligationCause::new( + impl_ty_span, + impl_ty_hir_id, + ObligationCauseCode::ItemObligation(trait_ty.def_id), + ); + + let predicates = tcx.projection_predicates(trait_ty.def_id); + + debug!("compare_projection_bounds: projection_predicates={:?}", predicates); + + for predicate in predicates { + let concrete_ty_predicate = match predicate.kind() { + ty::PredicateKind::Trait(poly_tr, c) => poly_tr + .map_bound(|tr| { + let trait_substs = translate_predicate_substs(tr.trait_ref.substs); + ty::TraitRef { def_id: tr.def_id(), substs: trait_substs } + }) + .with_constness(*c) + .to_predicate(tcx), + ty::PredicateKind::Projection(poly_projection) => poly_projection + .map_bound(|projection| { + let projection_substs = + translate_predicate_substs(projection.projection_ty.substs); + ty::ProjectionPredicate { + projection_ty: ty::ProjectionTy { + substs: projection_substs, + item_def_id: projection.projection_ty.item_def_id, + }, + ty: projection.ty.subst(tcx, rebased_substs), + } + }) + .to_predicate(tcx), + ty::PredicateKind::TypeOutlives(poly_outlives) => poly_outlives + .map_bound(|outlives| { + ty::OutlivesPredicate(impl_ty_value, outlives.1.subst(tcx, rebased_substs)) + }) + .to_predicate(tcx), + _ => bug!("unexepected projection predicate kind: `{:?}`", predicate), + }; + + let traits::Normalized { value: normalized_predicate, obligations } = traits::normalize( + &mut selcx, + param_env, + normalize_cause.clone(), + &concrete_ty_predicate, + ); + + debug!("compare_projection_bounds: normalized predicate = {:?}", normalized_predicate); + + inh.register_predicates(obligations); + inh.register_predicate(traits::Obligation::new( + cause.clone(), + param_env, + normalized_predicate, + )); + } + + // Check that all obligations are satisfied by the implementation's + // version. + if let Err(ref errors) = inh.fulfillment_cx.borrow_mut().select_all_or_error(&infcx) { + infcx.report_fulfillment_errors(errors, None, false); + return Err(ErrorReported); + } + + // Finally, resolve all regions. This catches wily misuses of + // lifetime parameters. + let fcx = FnCtxt::new(&inh, param_env, impl_ty_hir_id); + fcx.regionck_item(impl_ty_hir_id, impl_ty_span, &[]); + + Ok(()) + }) +} + fn assoc_item_kind_str(impl_item: &ty::AssocItem) -> &'static str { match impl_item.kind { ty::AssocKind::Const => "const", diff --git a/src/librustc_typeck/check/expr.rs b/src/librustc_typeck/check/expr.rs index 6a00667637155..1eaa5a6c31e20 100644 --- a/src/librustc_typeck/check/expr.rs +++ b/src/librustc_typeck/check/expr.rs @@ -1447,9 +1447,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // of error recovery. self.write_field_index(expr.hir_id, index); if field.vis.is_accessible_from(def_scope, self.tcx) { - let adjustments = autoderef.adjust_steps(self); + let adjustments = self.adjust_steps(&autoderef); self.apply_adjustments(base, adjustments); - autoderef.finalize(self); + self.register_predicates(autoderef.into_obligations()); self.tcx.check_stability(field.did, Some(expr.hir_id), expr.span); return field_ty; @@ -1462,9 +1462,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if let Ok(index) = fstr.parse::() { if fstr == index.to_string() { if let Some(field_ty) = tys.get(index) { - let adjustments = autoderef.adjust_steps(self); + let adjustments = self.adjust_steps(&autoderef); self.apply_adjustments(base, adjustments); - autoderef.finalize(self); + self.register_predicates(autoderef.into_obligations()); self.write_field_index(expr.hir_id, index); return field_ty.expect_ty(); @@ -1475,7 +1475,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { _ => {} } } - autoderef.unambiguous_final_ty(self); + self.structurally_resolved_type(autoderef.span(), autoderef.final_ty(false)); if let Some((did, field_ty)) = private_candidate { self.ban_private_field_access(expr, expr_t, field, did); diff --git a/src/librustc_typeck/check/method/confirm.rs b/src/librustc_typeck/check/method/confirm.rs index 6844c9416af8a..1c3d23a3a241f 100644 --- a/src/librustc_typeck/check/method/confirm.rs +++ b/src/librustc_typeck/check/method/confirm.rs @@ -144,9 +144,10 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { }; assert_eq!(n, pick.autoderefs); - let mut adjustments = autoderef.adjust_steps(self); + let mut adjustments = self.adjust_steps(&autoderef); - let mut target = autoderef.unambiguous_final_ty(self); + let mut target = + self.structurally_resolved_type(autoderef.span(), autoderef.final_ty(false)); if let Some(mutbl) = pick.autoref { let region = self.next_region_var(infer::Autoref(self.span)); @@ -176,7 +177,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { assert!(pick.unsize.is_none()); } - autoderef.finalize(self); + self.register_predicates(autoderef.into_obligations()); // Write out the final adjustments. self.apply_adjustments(self.self_expr, adjustments); diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index efd23894d02d1..a3e34815d3182 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -3,7 +3,6 @@ use super::MethodError; use super::NoMatchData; use super::{CandidateSource, ImplSource, TraitSource}; -use crate::check::autoderef::{self, Autoderef}; use crate::check::FnCtxt; use crate::hir::def::DefKind; use crate::hir::def_id::DefId; @@ -30,6 +29,7 @@ use rustc_session::config::nightly_options; use rustc_session::lint; use rustc_span::def_id::LocalDefId; use rustc_span::{symbol::Ident, Span, Symbol, DUMMY_SP}; +use rustc_trait_selection::autoderef::{self, Autoderef}; use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt; use rustc_trait_selection::traits::query::method_autoderef::MethodAutoderefBadTy; use rustc_trait_selection::traits::query::method_autoderef::{ @@ -477,7 +477,7 @@ fn method_autoderef_steps<'tcx>( }) .collect(); - let final_ty = autoderef.maybe_ambiguous_final_ty(); + let final_ty = autoderef.final_ty(true); let opt_bad_ty = match final_ty.kind { ty::Infer(ty::TyVar(_)) | ty::Error(_) => Some(MethodAutoderefBadTy { reached_raw_pointer, diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 775441cb74666..1594d65e9bdee 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -2281,7 +2281,7 @@ fn check_impl_items_against_trait<'tcx>( &ty_trait_item, impl_trait_ref, opt_trait_span, - ) + ); } else { let mut err = struct_span_err!( tcx.sess, diff --git a/src/librustc_typeck/check/place_op.rs b/src/librustc_typeck/check/place_op.rs index d1c22cd1ac03e..b7c8f310a1414 100644 --- a/src/librustc_typeck/check/place_op.rs +++ b/src/librustc_typeck/check/place_op.rs @@ -1,4 +1,3 @@ -use crate::check::autoderef::Autoderef; use crate::check::method::MethodCallee; use crate::check::{FnCtxt, PlaceOp}; use rustc_hir as hir; @@ -9,6 +8,7 @@ use rustc_middle::ty::adjustment::{AllowTwoPhase, AutoBorrow, AutoBorrowMutabili use rustc_middle::ty::{self, Ty}; use rustc_span::symbol::{sym, Ident}; use rustc_span::Span; +use rustc_trait_selection::autoderef::Autoderef; impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// Type-check `*oprnd_expr` with `oprnd_expr` type-checked already. @@ -57,7 +57,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { while result.is_none() && autoderef.next().is_some() { result = self.try_index_step(expr, base_expr, &autoderef, idx_ty); } - autoderef.finalize(self); + self.register_predicates(autoderef.into_obligations()); result } @@ -73,7 +73,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { autoderef: &Autoderef<'a, 'tcx>, index_ty: Ty<'tcx>, ) -> Option<(/*index type*/ Ty<'tcx>, /*element type*/ Ty<'tcx>)> { - let adjusted_ty = autoderef.unambiguous_final_ty(self); + let adjusted_ty = + self.structurally_resolved_type(autoderef.span(), autoderef.final_ty(false)); debug!( "try_index_step(expr={:?}, base_expr={:?}, adjusted_ty={:?}, \ index_ty={:?})", @@ -105,7 +106,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { debug!("try_index_step: success, using overloaded indexing"); let method = self.register_infer_ok_obligations(ok); - let mut adjustments = autoderef.adjust_steps(self); + let mut adjustments = self.adjust_steps(autoderef); if let ty::Ref(region, _, hir::Mutability::Not) = method.sig.inputs()[0].kind { adjustments.push(Adjustment { kind: Adjust::Borrow(AutoBorrow::Ref(region, AutoBorrowMutability::Not)), diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs index f3297ed674347..d1a86a7ee89a8 100644 --- a/src/librustc_typeck/check/wfcheck.rs +++ b/src/librustc_typeck/check/wfcheck.rs @@ -1118,7 +1118,7 @@ fn receiver_is_valid<'fcx, 'tcx>( ); if can_eq_self(potential_self_ty) { - autoderef.finalize(fcx); + fcx.register_predicates(autoderef.into_obligations()); if let Some(mut err) = fcx.demand_eqtype_with_origin(&cause, self_ty, potential_self_ty) diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 91266eeb9bab0..054165f2b0977 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -35,7 +35,7 @@ use rustc_middle::hir::map::Map; use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs}; use rustc_middle::mir::mono::Linkage; use rustc_middle::ty::query::Providers; -use rustc_middle::ty::subst::{InternalSubsts, Subst}; +use rustc_middle::ty::subst::InternalSubsts; use rustc_middle::ty::util::Discr; use rustc_middle::ty::util::IntTypeExt; use rustc_middle::ty::{self, AdtKind, Const, ToPolyTraitRef, Ty, TyCtxt}; @@ -1692,6 +1692,7 @@ fn explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicat let mut is_trait = None; let mut is_default_impl_trait = None; + let mut is_trait_associated_type = None; let icx = ItemCtxt::new(tcx, def_id); let constness = icx.default_constness_for_trait_bounds(); @@ -1701,7 +1702,12 @@ fn explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicat let mut predicates = UniquePredicates::new(); let ast_generics = match node { - Node::TraitItem(item) => &item.generics, + Node::TraitItem(item) => { + if let hir::TraitItemKind::Type(bounds, _) = item.kind { + is_trait_associated_type = Some((bounds, item.span)); + } + &item.generics + } Node::ImplItem(item) => &item.generics, @@ -1925,10 +1931,21 @@ fn explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicat } } - // Add predicates from associated type bounds. - if let Some((self_trait_ref, trait_items)) = is_trait { + // Add predicates from associated type bounds (`type X: Bound`) + if tcx.features().generic_associated_types { + // New behavior: bounds declared on associate type are predicates of that + // associated type. Not the default because it needs more testing. + if let Some((bounds, span)) = is_trait_associated_type { + let projection_ty = + tcx.mk_projection(def_id, InternalSubsts::identity_for_item(tcx, def_id)); + + predicates.extend(associated_item_bounds(tcx, def_id, bounds, projection_ty, span)) + } + } else if let Some((self_trait_ref, trait_items)) = is_trait { + // Current behavior: bounds declared on associate type are predicates + // of its parent trait. predicates.extend(trait_items.iter().flat_map(|trait_item_ref| { - associated_item_predicates(tcx, def_id, self_trait_ref, trait_item_ref) + trait_associated_item_predicates(tcx, def_id, self_trait_ref, trait_item_ref) })) } @@ -1958,7 +1975,7 @@ fn explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicat result } -fn associated_item_predicates( +fn trait_associated_item_predicates( tcx: TyCtxt<'tcx>, def_id: DefId, self_trait_ref: ty::TraitRef<'tcx>, @@ -1971,92 +1988,40 @@ fn associated_item_predicates( _ => return Vec::new(), }; - let is_gat = !tcx.generics_of(item_def_id).params.is_empty(); - - let mut had_error = false; - - let mut unimplemented_error = |arg_kind: &str| { - if !had_error { - tcx.sess - .struct_span_err( - trait_item.span, - &format!("{}-generic associated types are not yet implemented", arg_kind), - ) - .note( - "for more information, see issue #44265 \ - for more information", - ) - .emit(); - had_error = true; - } - }; - - let mk_bound_param = |param: &ty::GenericParamDef, _: &_| { - match param.kind { - ty::GenericParamDefKind::Lifetime => tcx - .mk_region(ty::RegionKind::ReLateBound( - ty::INNERMOST, - ty::BoundRegion::BrNamed(param.def_id, param.name), - )) - .into(), - // FIXME(generic_associated_types): Use bound types and constants - // once they are handled by the trait system. - ty::GenericParamDefKind::Type { .. } => { - unimplemented_error("type"); - tcx.ty_error().into() - } - ty::GenericParamDefKind::Const => { - unimplemented_error("const"); - tcx.const_error(tcx.type_of(param.def_id)).into() - } - } - }; + if !tcx.generics_of(item_def_id).params.is_empty() { + // For GATs the substs provided to the mk_projection call below are + // wrong. We should emit a feature gate error if we get here so skip + // this type. + tcx.sess.delay_span_bug(trait_item.span, "gats used without feature gate"); + return Vec::new(); + } - let bound_substs = if is_gat { - // Given: - // - // trait X<'a, B, const C: usize> { - // type T<'d, E, const F: usize>: Default; - // } - // - // We need to create predicates on the trait: - // - // for<'d, E, const F: usize> - // >::T<'d, E, const F: usize>: Sized + Default - // - // We substitute escaping bound parameters for the generic - // arguments to the associated type which are then bound by - // the `Binder` around the the predicate. - // - // FIXME(generic_associated_types): Currently only lifetimes are handled. - self_trait_ref.substs.extend_to(tcx, item_def_id.to_def_id(), mk_bound_param) - } else { - self_trait_ref.substs - }; + let assoc_ty = tcx.mk_projection( + tcx.hir().local_def_id(trait_item.hir_id).to_def_id(), + self_trait_ref.substs, + ); - let assoc_ty = - tcx.mk_projection(tcx.hir().local_def_id(trait_item.hir_id).to_def_id(), bound_substs); + associated_item_bounds(tcx, def_id, bounds, assoc_ty, trait_item.span) +} +fn associated_item_bounds( + tcx: TyCtxt<'tcx>, + def_id: DefId, + bounds: &'tcx [hir::GenericBound<'tcx>], + projection_ty: Ty<'tcx>, + span: Span, +) -> Vec<(ty::Predicate<'tcx>, Span)> { let bounds = AstConv::compute_bounds( &ItemCtxt::new(tcx, def_id), - assoc_ty, + projection_ty, bounds, SizedByDefault::Yes, - trait_item.span, + span, ); - let predicates = bounds.predicates(tcx, assoc_ty); + let predicates = bounds.predicates(tcx, projection_ty); - if is_gat { - // We use shifts to get the regions that we're substituting to - // be bound by the binders in the `Predicate`s rather that - // escaping. - let shifted_in = ty::fold::shift_vars(tcx, &predicates, 1); - let substituted = shifted_in.subst(tcx, bound_substs); - ty::fold::shift_out_vars(tcx, &substituted, 1) - } else { - predicates - } + predicates } /// Converts a specific `GenericBound` from the AST into a set of diff --git a/src/stage0.txt b/src/stage0.txt index 5e840b9db1994..769ec669bdc8d 100644 --- a/src/stage0.txt +++ b/src/stage0.txt @@ -12,7 +12,7 @@ # source tarball for a stable release you'll likely see `1.x.0` for rustc and # `0.(x+1).0` for Cargo where they were released on `date`. -date: 2020-06-03 +date: 2020-06-16 rustc: beta cargo: beta diff --git a/src/test/codegen/asm-multiple-options.rs b/src/test/codegen/asm-multiple-options.rs new file mode 100644 index 0000000000000..c702742bf1a63 --- /dev/null +++ b/src/test/codegen/asm-multiple-options.rs @@ -0,0 +1,53 @@ +// compile-flags: -O +// only-x86_64 + +#![crate_type = "rlib"] +#![feature(asm)] + +// CHECK-LABEL: @pure +// CHECK-NOT: asm +// CHECK: ret void +#[no_mangle] +pub unsafe fn pure(x: i32) { + let y: i32; + asm!("", out("ax") y, in("bx") x, options(pure), options(nomem)); +} + +pub static mut VAR: i32 = 0; +pub static mut DUMMY_OUTPUT: i32 = 0; + +// CHECK-LABEL: @readonly +// CHECK: call i32 asm +// CHECK: ret i32 1 +#[no_mangle] +pub unsafe fn readonly() -> i32 { + VAR = 1; + asm!("", out("ax") DUMMY_OUTPUT, options(pure), options(readonly)); + VAR +} + +// CHECK-LABEL: @nomem +// CHECK-NOT: store +// CHECK: call i32 asm +// CHECK: store +// CHECK: ret i32 2 +#[no_mangle] +pub unsafe fn nomem() -> i32 { + VAR = 1; + asm!("", out("ax") DUMMY_OUTPUT, options(pure), options(nomem)); + VAR = 2; + VAR +} + +// CHECK-LABEL: @not_nomem +// CHECK: store +// CHECK: call i32 asm +// CHECK: store +// CHECK: ret i32 2 +#[no_mangle] +pub unsafe fn not_nomem() -> i32 { + VAR = 1; + asm!("", out("ax") DUMMY_OUTPUT, options(pure), options(readonly)); + VAR = 2; + VAR +} diff --git a/src/test/ui/asm/duplicate-options.fixed b/src/test/ui/asm/duplicate-options.fixed new file mode 100644 index 0000000000000..f4672a50fd0f4 --- /dev/null +++ b/src/test/ui/asm/duplicate-options.fixed @@ -0,0 +1,26 @@ +// only-x86_64 +// run-rustfix + +#![feature(asm)] + +fn main() { + unsafe { + asm!("", options(nomem, )); + //~^ ERROR the `nomem` option was already provided + asm!("", options(att_syntax, )); + //~^ ERROR the `att_syntax` option was already provided + asm!("", options(nostack, att_syntax), options()); + //~^ ERROR the `nostack` option was already provided + asm!("", options(nostack, ), options(), options()); + //~^ ERROR the `nostack` option was already provided + //~| ERROR the `nostack` option was already provided + //~| ERROR the `nostack` option was already provided + asm!( + "", + options(nomem, noreturn), + options(att_syntax, ), //~ ERROR the `noreturn` option was already provided + options( nostack), //~ ERROR the `nomem` option was already provided + options(), //~ ERROR the `noreturn` option was already provided + ); + } +} diff --git a/src/test/ui/asm/duplicate-options.rs b/src/test/ui/asm/duplicate-options.rs new file mode 100644 index 0000000000000..80292d7521a9a --- /dev/null +++ b/src/test/ui/asm/duplicate-options.rs @@ -0,0 +1,26 @@ +// only-x86_64 +// run-rustfix + +#![feature(asm)] + +fn main() { + unsafe { + asm!("", options(nomem, nomem)); + //~^ ERROR the `nomem` option was already provided + asm!("", options(att_syntax, att_syntax)); + //~^ ERROR the `att_syntax` option was already provided + asm!("", options(nostack, att_syntax), options(nostack)); + //~^ ERROR the `nostack` option was already provided + asm!("", options(nostack, nostack), options(nostack), options(nostack)); + //~^ ERROR the `nostack` option was already provided + //~| ERROR the `nostack` option was already provided + //~| ERROR the `nostack` option was already provided + asm!( + "", + options(nomem, noreturn), + options(att_syntax, noreturn), //~ ERROR the `noreturn` option was already provided + options(nomem, nostack), //~ ERROR the `nomem` option was already provided + options(noreturn), //~ ERROR the `noreturn` option was already provided + ); + } +} diff --git a/src/test/ui/asm/duplicate-options.stderr b/src/test/ui/asm/duplicate-options.stderr new file mode 100644 index 0000000000000..cd8d743e031a5 --- /dev/null +++ b/src/test/ui/asm/duplicate-options.stderr @@ -0,0 +1,56 @@ +error: the `nomem` option was already provided + --> $DIR/duplicate-options.rs:8:33 + | +LL | asm!("", options(nomem, nomem)); + | ^^^^^ this option was already provided + +error: the `att_syntax` option was already provided + --> $DIR/duplicate-options.rs:10:38 + | +LL | asm!("", options(att_syntax, att_syntax)); + | ^^^^^^^^^^ this option was already provided + +error: the `nostack` option was already provided + --> $DIR/duplicate-options.rs:12:56 + | +LL | asm!("", options(nostack, att_syntax), options(nostack)); + | ^^^^^^^ this option was already provided + +error: the `nostack` option was already provided + --> $DIR/duplicate-options.rs:14:35 + | +LL | asm!("", options(nostack, nostack), options(nostack), options(nostack)); + | ^^^^^^^ this option was already provided + +error: the `nostack` option was already provided + --> $DIR/duplicate-options.rs:14:53 + | +LL | asm!("", options(nostack, nostack), options(nostack), options(nostack)); + | ^^^^^^^ this option was already provided + +error: the `nostack` option was already provided + --> $DIR/duplicate-options.rs:14:71 + | +LL | asm!("", options(nostack, nostack), options(nostack), options(nostack)); + | ^^^^^^^ this option was already provided + +error: the `noreturn` option was already provided + --> $DIR/duplicate-options.rs:21:33 + | +LL | options(att_syntax, noreturn), + | ^^^^^^^^ this option was already provided + +error: the `nomem` option was already provided + --> $DIR/duplicate-options.rs:22:21 + | +LL | options(nomem, nostack), + | ^^^^^ this option was already provided + +error: the `noreturn` option was already provided + --> $DIR/duplicate-options.rs:23:21 + | +LL | options(noreturn), + | ^^^^^^^^ this option was already provided + +error: aborting due to 9 previous errors + diff --git a/src/test/ui/asm/parse-error.rs b/src/test/ui/asm/parse-error.rs index fbf399d8b075c..538a3fde8fdeb 100644 --- a/src/test/ui/asm/parse-error.rs +++ b/src/test/ui/asm/parse-error.rs @@ -34,11 +34,6 @@ fn main() { //~^ ERROR expected one of asm!("", options(nomem, foo)); //~^ ERROR expected one of - asm!("", options(), options()); - //~^ ERROR asm options cannot be specified multiple times - asm!("", options(), options(), options()); - //~^ ERROR asm options cannot be specified multiple times - //~^^ ERROR asm options cannot be specified multiple times asm!("{}", options(), const foo); //~^ ERROR arguments are not allowed after options asm!("{a}", a = const foo, a = const bar); diff --git a/src/test/ui/asm/parse-error.stderr b/src/test/ui/asm/parse-error.stderr index ba7e8f7a03cca..dfbfc0abe3472 100644 --- a/src/test/ui/asm/parse-error.stderr +++ b/src/test/ui/asm/parse-error.stderr @@ -82,32 +82,8 @@ error: expected one of `)`, `att_syntax`, `nomem`, `noreturn`, `nostack`, `prese LL | asm!("", options(nomem, foo)); | ^^^ expected one of 8 possible tokens -error: asm options cannot be specified multiple times - --> $DIR/parse-error.rs:37:29 - | -LL | asm!("", options(), options()); - | --------- ^^^^^^^^^ duplicate options - | | - | previously here - -error: asm options cannot be specified multiple times - --> $DIR/parse-error.rs:39:29 - | -LL | asm!("", options(), options(), options()); - | --------- ^^^^^^^^^ duplicate options - | | - | previously here - -error: asm options cannot be specified multiple times - --> $DIR/parse-error.rs:39:40 - | -LL | asm!("", options(), options(), options()); - | --------- ^^^^^^^^^ duplicate options - | | - | previously here - error: arguments are not allowed after options - --> $DIR/parse-error.rs:42:31 + --> $DIR/parse-error.rs:37:31 | LL | asm!("{}", options(), const foo); | --------- ^^^^^^^^^ argument @@ -115,7 +91,7 @@ LL | asm!("{}", options(), const foo); | previous options error: duplicate argument named `a` - --> $DIR/parse-error.rs:44:36 + --> $DIR/parse-error.rs:39:36 | LL | asm!("{a}", a = const foo, a = const bar); | ------------- ^^^^^^^^^^^^^ duplicate argument @@ -123,7 +99,7 @@ LL | asm!("{a}", a = const foo, a = const bar); | previously here error: argument never used - --> $DIR/parse-error.rs:44:36 + --> $DIR/parse-error.rs:39:36 | LL | asm!("{a}", a = const foo, a = const bar); | ^^^^^^^^^^^^^ argument never used @@ -131,13 +107,13 @@ LL | asm!("{a}", a = const foo, a = const bar); = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {1} */"` error: explicit register arguments cannot have names - --> $DIR/parse-error.rs:47:18 + --> $DIR/parse-error.rs:42:18 | LL | asm!("", a = in("eax") foo); | ^^^^^^^^^^^^^^^^^ error: named arguments cannot follow explicit register arguments - --> $DIR/parse-error.rs:49:36 + --> $DIR/parse-error.rs:44:36 | LL | asm!("{a}", in("eax") foo, a = const bar); | ------------- ^^^^^^^^^^^^^ named argument @@ -145,7 +121,7 @@ LL | asm!("{a}", in("eax") foo, a = const bar); | explicit register argument error: named arguments cannot follow explicit register arguments - --> $DIR/parse-error.rs:51:36 + --> $DIR/parse-error.rs:46:36 | LL | asm!("{a}", in("eax") foo, a = const bar); | ------------- ^^^^^^^^^^^^^ named argument @@ -153,7 +129,7 @@ LL | asm!("{a}", in("eax") foo, a = const bar); | explicit register argument error: positional arguments cannot follow named arguments or explicit register arguments - --> $DIR/parse-error.rs:53:36 + --> $DIR/parse-error.rs:48:36 | LL | asm!("{1}", in("eax") foo, const bar); | ------------- ^^^^^^^^^ positional argument @@ -161,19 +137,19 @@ LL | asm!("{1}", in("eax") foo, const bar); | explicit register argument error: expected one of `const`, `in`, `inlateout`, `inout`, `lateout`, `options`, `out`, or `sym`, found `""` - --> $DIR/parse-error.rs:55:29 + --> $DIR/parse-error.rs:50:29 | LL | asm!("", options(), ""); | ^^ expected one of 8 possible tokens error: expected one of `const`, `in`, `inlateout`, `inout`, `lateout`, `options`, `out`, or `sym`, found `"{}"` - --> $DIR/parse-error.rs:57:33 + --> $DIR/parse-error.rs:52:33 | LL | asm!("{}", in(reg) foo, "{}", out(reg) foo); | ^^^^ expected one of 8 possible tokens error: asm template must be a string literal - --> $DIR/parse-error.rs:59:14 + --> $DIR/parse-error.rs:54:14 | LL | asm!(format!("{{{}}}", 0), in(reg) foo); | ^^^^^^^^^^^^^^^^^^^^ @@ -181,12 +157,12 @@ LL | asm!(format!("{{{}}}", 0), in(reg) foo); = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) error: asm template must be a string literal - --> $DIR/parse-error.rs:61:21 + --> $DIR/parse-error.rs:56:21 | LL | asm!("{1}", format!("{{{}}}", 0), in(reg) foo, out(reg) bar); | ^^^^^^^^^^^^^^^^^^^^ | = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) -error: aborting due to 28 previous errors +error: aborting due to 25 previous errors diff --git a/src/test/ui/associated-types/hr-associated-type-bound-1.rs b/src/test/ui/associated-types/hr-associated-type-bound-1.rs new file mode 100644 index 0000000000000..497b86eeab88d --- /dev/null +++ b/src/test/ui/associated-types/hr-associated-type-bound-1.rs @@ -0,0 +1,18 @@ +trait X<'a> +where + for<'b> >::U: Clone, +{ + type U: ?Sized; + fn f(&self, x: &Self::U) { + ::clone(x); + } +} + +impl X<'_> for i32 { + type U = str; + //~^ ERROR the trait bound `for<'b> >::U: std::clone::Clone` +} + +fn main() { + 1i32.f("abc"); +} diff --git a/src/test/ui/associated-types/hr-associated-type-bound-1.stderr b/src/test/ui/associated-types/hr-associated-type-bound-1.stderr new file mode 100644 index 0000000000000..7ef2faef9c6e7 --- /dev/null +++ b/src/test/ui/associated-types/hr-associated-type-bound-1.stderr @@ -0,0 +1,19 @@ +error[E0277]: the trait bound `for<'b> >::U: std::clone::Clone` is not satisfied + --> $DIR/hr-associated-type-bound-1.rs:12:14 + | +LL | trait X<'a> + | - required by a bound in this +LL | where +LL | for<'b> >::U: Clone, + | ----- required by this bound in `X` +... +LL | type U = str; + | ^^^ the trait `for<'b> std::clone::Clone` is not implemented for `>::U` + | + = help: the following implementations were found: + <&T as std::clone::Clone> + <&mut T as std::clone::Clone> + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/associated-types/hr-associated-type-bound-2.rs b/src/test/ui/associated-types/hr-associated-type-bound-2.rs new file mode 100644 index 0000000000000..7ff0fede28cfe --- /dev/null +++ b/src/test/ui/associated-types/hr-associated-type-bound-2.rs @@ -0,0 +1,21 @@ +trait X<'a> +where + for<'b> >::U: Clone, +{ + type U: ?Sized; + fn f(&self, x: &Self::U) { + ::clone(x); + } +} + +impl X<'_> for u32 +where + for<'b> >::U: Clone, +{ + type U = str; +} + +fn main() { + 1u32.f("abc"); + //~^ ERROR no method named `f` found for type `u32` in the current scope +} diff --git a/src/test/ui/associated-types/hr-associated-type-bound-2.stderr b/src/test/ui/associated-types/hr-associated-type-bound-2.stderr new file mode 100644 index 0000000000000..2a364d349d77e --- /dev/null +++ b/src/test/ui/associated-types/hr-associated-type-bound-2.stderr @@ -0,0 +1,13 @@ +error[E0599]: no method named `f` found for type `u32` in the current scope + --> $DIR/hr-associated-type-bound-2.rs:19:10 + | +LL | 1u32.f("abc"); + | ^ method not found in `u32` + | + = note: the method `f` exists but the following trait bounds were not satisfied: + `>::U: std::clone::Clone` + which is required by `u32: X` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0599`. diff --git a/src/test/ui/associated-types/hr-associated-type-bound-object.rs b/src/test/ui/associated-types/hr-associated-type-bound-object.rs new file mode 100644 index 0000000000000..7c64ae38caf60 --- /dev/null +++ b/src/test/ui/associated-types/hr-associated-type-bound-object.rs @@ -0,0 +1,14 @@ +trait X<'a> +where + for<'b> >::U: Clone, +{ + type U: ?Sized; +} +fn f<'a, T: X<'a> + ?Sized>(x: &>::U) { + //~^ ERROR the trait bound `for<'b> >::U: std::clone::Clone` is not satisfied + <>::U>::clone(x); +} + +pub fn main() { + f::>("abc"); +} diff --git a/src/test/ui/associated-types/hr-associated-type-bound-object.stderr b/src/test/ui/associated-types/hr-associated-type-bound-object.stderr new file mode 100644 index 0000000000000..db966875c708f --- /dev/null +++ b/src/test/ui/associated-types/hr-associated-type-bound-object.stderr @@ -0,0 +1,19 @@ +error[E0277]: the trait bound `for<'b> >::U: std::clone::Clone` is not satisfied + --> $DIR/hr-associated-type-bound-object.rs:7:13 + | +LL | trait X<'a> + | - required by a bound in this +LL | where +LL | for<'b> >::U: Clone, + | ----- required by this bound in `X` +... +LL | fn f<'a, T: X<'a> + ?Sized>(x: &>::U) { + | ^^^^^ the trait `for<'b> std::clone::Clone` is not implemented for `>::U` + | + = help: the following implementations were found: + <&T as std::clone::Clone> + <&mut T as std::clone::Clone> + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/associated-types/hr-associated-type-bound-param-1.rs b/src/test/ui/associated-types/hr-associated-type-bound-param-1.rs new file mode 100644 index 0000000000000..a65f8a8c498b7 --- /dev/null +++ b/src/test/ui/associated-types/hr-associated-type-bound-param-1.rs @@ -0,0 +1,20 @@ +trait Y<'a, T: ?Sized> +where + T: Y<'a, Self>, + for<'b> >::V: Clone, + for<'b> >::V: Clone, +{ + type V: ?Sized; + fn g(&self, x: &Self::V) { + ::clone(x); + } +} + +impl<'a> Y<'a, u8> for u8 { + type V = str; + //~^ ERROR the trait bound `for<'b> >::V: std::clone::Clone` is not satisfied +} + +fn main() { + 1u8.g("abc"); +} diff --git a/src/test/ui/associated-types/hr-associated-type-bound-param-1.stderr b/src/test/ui/associated-types/hr-associated-type-bound-param-1.stderr new file mode 100644 index 0000000000000..347a5818dce31 --- /dev/null +++ b/src/test/ui/associated-types/hr-associated-type-bound-param-1.stderr @@ -0,0 +1,19 @@ +error[E0277]: the trait bound `for<'b> >::V: std::clone::Clone` is not satisfied + --> $DIR/hr-associated-type-bound-param-1.rs:14:14 + | +LL | trait Y<'a, T: ?Sized> + | - required by a bound in this +... +LL | for<'b> >::V: Clone, + | ----- required by this bound in `Y` +... +LL | type V = str; + | ^^^ the trait `for<'b> std::clone::Clone` is not implemented for `>::V` + | + = help: the following implementations were found: + <&T as std::clone::Clone> + <&mut T as std::clone::Clone> + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/associated-types/hr-associated-type-bound-param-2.rs b/src/test/ui/associated-types/hr-associated-type-bound-param-2.rs new file mode 100644 index 0000000000000..9f849b0327669 --- /dev/null +++ b/src/test/ui/associated-types/hr-associated-type-bound-param-2.rs @@ -0,0 +1,21 @@ +trait Z<'a, T: ?Sized> +where + T: Z<'a, u16>, + //~^ the trait bound `for<'b> >::W: std::clone::Clone` is not satisfied + //~| the trait bound `for<'b> >::W: std::clone::Clone` is not satisfied + for<'b> >::W: Clone, +{ + type W: ?Sized; + fn h(&self, x: &T::W) { + ::clone(x); + } +} + +impl<'a> Z<'a, u16> for u16 { + type W = str; + //~^ ERROR the trait bound `for<'b> >::W: std::clone::Clone +} + +fn main() { + 1u16.h("abc"); +} diff --git a/src/test/ui/associated-types/hr-associated-type-bound-param-2.stderr b/src/test/ui/associated-types/hr-associated-type-bound-param-2.stderr new file mode 100644 index 0000000000000..e06777e36a8c5 --- /dev/null +++ b/src/test/ui/associated-types/hr-associated-type-bound-param-2.stderr @@ -0,0 +1,51 @@ +error[E0277]: the trait bound `for<'b> >::W: std::clone::Clone` is not satisfied + --> $DIR/hr-associated-type-bound-param-2.rs:3:8 + | +LL | trait Z<'a, T: ?Sized> + | - required by a bound in this +LL | where +LL | T: Z<'a, u16>, + | ^^^^^^^^^^ the trait `for<'b> std::clone::Clone` is not implemented for `>::W` +... +LL | for<'b> >::W: Clone, + | ----- required by this bound in `Z` + | + = help: the following implementations were found: + <&T as std::clone::Clone> + <&mut T as std::clone::Clone> + +error[E0277]: the trait bound `for<'b> >::W: std::clone::Clone` is not satisfied + --> $DIR/hr-associated-type-bound-param-2.rs:15:14 + | +LL | trait Z<'a, T: ?Sized> + | - required by a bound in this +... +LL | for<'b> >::W: Clone, + | ----- required by this bound in `Z` +... +LL | type W = str; + | ^^^ the trait `for<'b> std::clone::Clone` is not implemented for `>::W` + | + = help: the following implementations were found: + <&T as std::clone::Clone> + <&mut T as std::clone::Clone> + +error[E0277]: the trait bound `for<'b> >::W: std::clone::Clone` is not satisfied + --> $DIR/hr-associated-type-bound-param-2.rs:3:8 + | +LL | trait Z<'a, T: ?Sized> + | - required by a bound in this +LL | where +LL | T: Z<'a, u16>, + | ^^^^^^^^^^ the trait `for<'b> std::clone::Clone` is not implemented for `>::W` +... +LL | for<'b> >::W: Clone, + | ----- required by this bound in `Z` + | + = help: the following implementations were found: + <&T as std::clone::Clone> + <&mut T as std::clone::Clone> + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/associated-types/hr-associated-type-bound-param-3.rs b/src/test/ui/associated-types/hr-associated-type-bound-param-3.rs new file mode 100644 index 0000000000000..9aca59f8ce6d7 --- /dev/null +++ b/src/test/ui/associated-types/hr-associated-type-bound-param-3.rs @@ -0,0 +1,21 @@ +// ignore-tidy-linelength + +trait X<'a, T> +where + for<'b> T: X<'b, T>, + for<'b> >::U: Clone, +{ + type U: ?Sized; + fn f(x: &>::U) { + <>::U>::clone(x); + } +} + +impl X<'_, (T,)> for (S,) { + type U = str; + //~^ ERROR the trait bound `for<'b> <(T,) as X<'b, (T,)>>::U: std::clone::Clone` is not satisfied +} + +pub fn main() { + <(i32,) as X<(i32,)>>::f("abc"); +} diff --git a/src/test/ui/associated-types/hr-associated-type-bound-param-3.stderr b/src/test/ui/associated-types/hr-associated-type-bound-param-3.stderr new file mode 100644 index 0000000000000..ff56f60e4c9e5 --- /dev/null +++ b/src/test/ui/associated-types/hr-associated-type-bound-param-3.stderr @@ -0,0 +1,19 @@ +error[E0277]: the trait bound `for<'b> <(T,) as X<'b, (T,)>>::U: std::clone::Clone` is not satisfied + --> $DIR/hr-associated-type-bound-param-3.rs:15:14 + | +LL | trait X<'a, T> + | - required by a bound in this +... +LL | for<'b> >::U: Clone, + | ----- required by this bound in `X` +... +LL | type U = str; + | ^^^ the trait `for<'b> std::clone::Clone` is not implemented for `<(T,) as X<'b, (T,)>>::U` + | + = help: the following implementations were found: + <&T as std::clone::Clone> + <&mut T as std::clone::Clone> + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/associated-types/hr-associated-type-bound-param-4.rs b/src/test/ui/associated-types/hr-associated-type-bound-param-4.rs new file mode 100644 index 0000000000000..ffe43c674c3dc --- /dev/null +++ b/src/test/ui/associated-types/hr-associated-type-bound-param-4.rs @@ -0,0 +1,19 @@ +trait X<'a, T> +where + for<'b> (T,): X<'b, T>, + for<'b> <(T,) as X<'b, T>>::U: Clone, +{ + type U: ?Sized; + fn f(x: &<(T,) as X<'_, T>>::U) { + <<(T,) as X<'_, T>>::U>::clone(x); + } +} + +impl X<'_, T> for (S,) { + type U = str; + //~^ ERROR the trait bound `for<'b> <(T,) as X<'b, T>>::U: std::clone::Clone` is not satisfied +} + +pub fn main() { + <(i32,) as X>::f("abc"); +} diff --git a/src/test/ui/associated-types/hr-associated-type-bound-param-4.stderr b/src/test/ui/associated-types/hr-associated-type-bound-param-4.stderr new file mode 100644 index 0000000000000..c41efb8b6e1a2 --- /dev/null +++ b/src/test/ui/associated-types/hr-associated-type-bound-param-4.stderr @@ -0,0 +1,19 @@ +error[E0277]: the trait bound `for<'b> <(T,) as X<'b, T>>::U: std::clone::Clone` is not satisfied + --> $DIR/hr-associated-type-bound-param-4.rs:13:14 + | +LL | trait X<'a, T> + | - required by a bound in this +... +LL | for<'b> <(T,) as X<'b, T>>::U: Clone, + | ----- required by this bound in `X` +... +LL | type U = str; + | ^^^ the trait `for<'b> std::clone::Clone` is not implemented for `<(T,) as X<'b, T>>::U` + | + = help: the following implementations were found: + <&T as std::clone::Clone> + <&mut T as std::clone::Clone> + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/associated-types/hr-associated-type-bound-param-5.rs b/src/test/ui/associated-types/hr-associated-type-bound-param-5.rs new file mode 100644 index 0000000000000..dcca0b3ce92aa --- /dev/null +++ b/src/test/ui/associated-types/hr-associated-type-bound-param-5.rs @@ -0,0 +1,41 @@ +// ignore-tidy-linelength + +trait Cycle: Sized { + type Next: Cycle; +} + +impl Cycle for Box { + type Next = Vec; +} + +impl Cycle for Vec { + type Next = Box; +} + +trait X<'a, T: Cycle + for<'b> X<'b, T>> +where + for<'b> >::U: Clone, + for<'b> T::Next: X<'b, T::Next>, + for<'b> >::U: Clone, +{ + type U: ?Sized; + fn f(x: &>::U) { + <>::U>::clone(x); + } +} + +impl X<'_, Vec> for S { + type U = str; + //~^ ERROR the trait bound `for<'b> as X<'b, std::boxed::Box>>::U: std::clone::Clone` is not satisfied + //~| ERROR the trait bound `for<'b> as X<'b, std::vec::Vec>>::U: std::clone::Clone` is not satisfied +} + +impl X<'_, Box> for S { + type U = str; + //~^ ERROR the trait bound `for<'b> as X<'b, std::boxed::Box>>::U: std::clone::Clone` is not satisfied + //~| ERROR the trait bound `for<'b> as X<'b, std::vec::Vec>>::U: std::clone::Clone` is not satisfied +} + +pub fn main() { + >>::f("abc"); +} diff --git a/src/test/ui/associated-types/hr-associated-type-bound-param-5.stderr b/src/test/ui/associated-types/hr-associated-type-bound-param-5.stderr new file mode 100644 index 0000000000000..39c191e974777 --- /dev/null +++ b/src/test/ui/associated-types/hr-associated-type-bound-param-5.stderr @@ -0,0 +1,67 @@ +error[E0277]: the trait bound `for<'b> as X<'b, std::boxed::Box>>::U: std::clone::Clone` is not satisfied + --> $DIR/hr-associated-type-bound-param-5.rs:28:14 + | +LL | trait X<'a, T: Cycle + for<'b> X<'b, T>> + | - required by a bound in this +... +LL | for<'b> >::U: Clone, + | ----- required by this bound in `X` +... +LL | type U = str; + | ^^^ the trait `for<'b> std::clone::Clone` is not implemented for ` as X<'b, std::boxed::Box>>::U` + | + = help: the following implementations were found: + <&T as std::clone::Clone> + <&mut T as std::clone::Clone> + +error[E0277]: the trait bound `for<'b> as X<'b, std::vec::Vec>>::U: std::clone::Clone` is not satisfied + --> $DIR/hr-associated-type-bound-param-5.rs:28:14 + | +LL | trait X<'a, T: Cycle + for<'b> X<'b, T>> + | - required by a bound in this +LL | where +LL | for<'b> >::U: Clone, + | ----- required by this bound in `X` +... +LL | type U = str; + | ^^^ the trait `for<'b> std::clone::Clone` is not implemented for ` as X<'b, std::vec::Vec>>::U` + | + = help: the following implementations were found: + <&T as std::clone::Clone> + <&mut T as std::clone::Clone> + +error[E0277]: the trait bound `for<'b> as X<'b, std::vec::Vec>>::U: std::clone::Clone` is not satisfied + --> $DIR/hr-associated-type-bound-param-5.rs:34:14 + | +LL | trait X<'a, T: Cycle + for<'b> X<'b, T>> + | - required by a bound in this +... +LL | for<'b> >::U: Clone, + | ----- required by this bound in `X` +... +LL | type U = str; + | ^^^ the trait `for<'b> std::clone::Clone` is not implemented for ` as X<'b, std::vec::Vec>>::U` + | + = help: the following implementations were found: + <&T as std::clone::Clone> + <&mut T as std::clone::Clone> + +error[E0277]: the trait bound `for<'b> as X<'b, std::boxed::Box>>::U: std::clone::Clone` is not satisfied + --> $DIR/hr-associated-type-bound-param-5.rs:34:14 + | +LL | trait X<'a, T: Cycle + for<'b> X<'b, T>> + | - required by a bound in this +LL | where +LL | for<'b> >::U: Clone, + | ----- required by this bound in `X` +... +LL | type U = str; + | ^^^ the trait `for<'b> std::clone::Clone` is not implemented for ` as X<'b, std::boxed::Box>>::U` + | + = help: the following implementations were found: + <&T as std::clone::Clone> + <&mut T as std::clone::Clone> + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/associated-types/hr-associated-type-bound-param-6.rs b/src/test/ui/associated-types/hr-associated-type-bound-param-6.rs new file mode 100644 index 0000000000000..4b8018cb43024 --- /dev/null +++ b/src/test/ui/associated-types/hr-associated-type-bound-param-6.rs @@ -0,0 +1,20 @@ +trait X<'a, T> +where + for<'b> T: X<'b, T>, + for<'b> >::U: Clone, +{ + type U: ?Sized; + fn f(x: &>::U) { + <>::U>::clone(x); + } +} + +impl X<'_, T> for (S,) { + //~^ ERROR the trait bound `for<'b> T: X<'b, T>` is not satisfied + type U = str; + //~^ ERROR the trait bound `for<'b> >::U: std::clone::Clone` is not satisfied +} + +pub fn main() { + <(i32,) as X>::f("abc"); +} diff --git a/src/test/ui/associated-types/hr-associated-type-bound-param-6.stderr b/src/test/ui/associated-types/hr-associated-type-bound-param-6.stderr new file mode 100644 index 0000000000000..83845d3a9410e --- /dev/null +++ b/src/test/ui/associated-types/hr-associated-type-bound-param-6.stderr @@ -0,0 +1,36 @@ +error[E0277]: the trait bound `for<'b> >::U: std::clone::Clone` is not satisfied + --> $DIR/hr-associated-type-bound-param-6.rs:14:14 + | +LL | trait X<'a, T> + | - required by a bound in this +... +LL | for<'b> >::U: Clone, + | ----- required by this bound in `X` +... +LL | type U = str; + | ^^^ the trait `for<'b> std::clone::Clone` is not implemented for `>::U` + | + = help: the following implementations were found: + <&T as std::clone::Clone> + <&mut T as std::clone::Clone> + +error[E0277]: the trait bound `for<'b> T: X<'b, T>` is not satisfied + --> $DIR/hr-associated-type-bound-param-6.rs:12:12 + | +LL | trait X<'a, T> + | - required by a bound in this +LL | where +LL | for<'b> T: X<'b, T>, + | -------- required by this bound in `X` +... +LL | impl X<'_, T> for (S,) { + | ^^^^^^^^ the trait `for<'b> X<'b, T>` is not implemented for `T` + | +help: consider restricting type parameter `T` + | +LL | impl X<'b, T>> X<'_, T> for (S,) { + | ^^^^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/associated-types/hr-associated-type-projection-1.rs b/src/test/ui/associated-types/hr-associated-type-projection-1.rs new file mode 100644 index 0000000000000..0d4567a55fc99 --- /dev/null +++ b/src/test/ui/associated-types/hr-associated-type-projection-1.rs @@ -0,0 +1,21 @@ +trait UnsafeCopy<'a, T: Copy> +where + for<'b> >::Item: std::ops::Deref, +{ + type Item; + + fn bug(item: &Self::Item) -> () { + let x: T = **item; + &x as *const _; + } +} + +impl UnsafeCopy<'_, T> for T { + //~^ ERROR the trait bound `>::Item: std::ops::Deref` is not satisfied + type Item = T; + //~^ ERROR the trait bound `for<'b> >::Item: std::ops::Deref +} + +pub fn main() { + <&'static str>::bug(&""); +} diff --git a/src/test/ui/associated-types/hr-associated-type-projection-1.stderr b/src/test/ui/associated-types/hr-associated-type-projection-1.stderr new file mode 100644 index 0000000000000..5ab57410c441b --- /dev/null +++ b/src/test/ui/associated-types/hr-associated-type-projection-1.stderr @@ -0,0 +1,30 @@ +error[E0277]: the trait bound `for<'b> >::Item: std::ops::Deref` is not satisfied + --> $DIR/hr-associated-type-projection-1.rs:15:17 + | +LL | trait UnsafeCopy<'a, T: Copy> + | ---------- required by a bound in this +LL | where +LL | for<'b> >::Item: std::ops::Deref, + | --------------------------- required by this bound in `UnsafeCopy` +... +LL | type Item = T; + | ^ the trait `for<'b> std::ops::Deref` is not implemented for `>::Item` + | + = help: the following implementations were found: + <&T as std::ops::Deref> + <&mut T as std::ops::Deref> + +error[E0277]: the trait bound `>::Item: std::ops::Deref` is not satisfied + --> $DIR/hr-associated-type-projection-1.rs:13:33 + | +LL | impl UnsafeCopy<'_, T> for T { + | ^^^^^^^^^^^^^^^^^ the trait `std::ops::Deref` is not implemented for `>::Item` + | +help: consider further restricting the associated type + | +LL | impl UnsafeCopy<'_, T> for T where >::Item: std::ops::Deref { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/feature-gates/feature-gate-generic_associated_types.rs b/src/test/ui/feature-gates/feature-gate-generic_associated_types.rs index 7ff348aca7cc1..17548d7b9e88c 100644 --- a/src/test/ui/feature-gates/feature-gate-generic_associated_types.rs +++ b/src/test/ui/feature-gates/feature-gate-generic_associated_types.rs @@ -3,11 +3,9 @@ use std::ops::Deref; trait PointerFamily { type Pointer: Deref; //~^ ERROR generic associated types are unstable - //~| ERROR type-generic associated types are not yet implemented type Pointer2: Deref where T: Clone, U: Clone; //~^ ERROR generic associated types are unstable //~| ERROR where clauses on associated types are unstable - //~| ERROR type-generic associated types are not yet implemented } struct Foo; diff --git a/src/test/ui/feature-gates/feature-gate-generic_associated_types.stderr b/src/test/ui/feature-gates/feature-gate-generic_associated_types.stderr index a0e06cb2b6795..8499b1ab70f5d 100644 --- a/src/test/ui/feature-gates/feature-gate-generic_associated_types.stderr +++ b/src/test/ui/feature-gates/feature-gate-generic_associated_types.stderr @@ -8,7 +8,7 @@ LL | type Pointer: Deref; = help: add `#![feature(generic_associated_types)]` to the crate attributes to enable error[E0658]: generic associated types are unstable - --> $DIR/feature-gate-generic_associated_types.rs:7:5 + --> $DIR/feature-gate-generic_associated_types.rs:6:5 | LL | type Pointer2: Deref where T: Clone, U: Clone; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -17,7 +17,7 @@ LL | type Pointer2: Deref where T: Clone, U: Clone; = help: add `#![feature(generic_associated_types)]` to the crate attributes to enable error[E0658]: where clauses on associated types are unstable - --> $DIR/feature-gate-generic_associated_types.rs:7:5 + --> $DIR/feature-gate-generic_associated_types.rs:6:5 | LL | type Pointer2: Deref where T: Clone, U: Clone; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -26,7 +26,7 @@ LL | type Pointer2: Deref where T: Clone, U: Clone; = help: add `#![feature(generic_associated_types)]` to the crate attributes to enable error[E0658]: generic associated types are unstable - --> $DIR/feature-gate-generic_associated_types.rs:16:5 + --> $DIR/feature-gate-generic_associated_types.rs:14:5 | LL | type Pointer = Box; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -35,7 +35,7 @@ LL | type Pointer = Box; = help: add `#![feature(generic_associated_types)]` to the crate attributes to enable error[E0658]: generic associated types are unstable - --> $DIR/feature-gate-generic_associated_types.rs:18:5 + --> $DIR/feature-gate-generic_associated_types.rs:16:5 | LL | type Pointer2 = Box; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -44,7 +44,7 @@ LL | type Pointer2 = Box; = help: add `#![feature(generic_associated_types)]` to the crate attributes to enable error[E0658]: where clauses on associated types are unstable - --> $DIR/feature-gate-generic_associated_types.rs:23:5 + --> $DIR/feature-gate-generic_associated_types.rs:21:5 | LL | type Assoc where Self: Sized; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -53,7 +53,7 @@ LL | type Assoc where Self: Sized; = help: add `#![feature(generic_associated_types)]` to the crate attributes to enable error[E0658]: where clauses on associated types are unstable - --> $DIR/feature-gate-generic_associated_types.rs:28:5 + --> $DIR/feature-gate-generic_associated_types.rs:26:5 | LL | type Assoc where Self: Sized = Foo; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -61,22 +61,6 @@ LL | type Assoc where Self: Sized = Foo; = note: see issue #44265 for more information = help: add `#![feature(generic_associated_types)]` to the crate attributes to enable -error: type-generic associated types are not yet implemented - --> $DIR/feature-gate-generic_associated_types.rs:4:5 - | -LL | type Pointer: Deref; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: for more information, see issue #44265 for more information - -error: type-generic associated types are not yet implemented - --> $DIR/feature-gate-generic_associated_types.rs:7:5 - | -LL | type Pointer2: Deref where T: Clone, U: Clone; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: for more information, see issue #44265 for more information - -error: aborting due to 9 previous errors +error: aborting due to 7 previous errors For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/generic-associated-types/collections-project-default.rs b/src/test/ui/generic-associated-types/collections-project-default.rs new file mode 100644 index 0000000000000..5fbae02573c62 --- /dev/null +++ b/src/test/ui/generic-associated-types/collections-project-default.rs @@ -0,0 +1,72 @@ +#![allow(incomplete_features)] +#![feature(generic_associated_types)] +#![feature(associated_type_defaults)] + +// A Collection trait and collection families. Based on +// http://smallcultfollowing.com/babysteps/blog/2016/11/03/ +// associated-type-constructors-part-2-family-traits/ + +// check that we don't normalize with trait defaults. + +trait Collection { + type Iter<'iter>: Iterator where T: 'iter; + type Family: CollectionFamily; + // Test associated type defaults with parameters + type Sibling: Collection = + <>::Family as CollectionFamily>::Member; + + fn empty() -> Self; + + fn add(&mut self, value: T); + + fn iterate<'iter>(&'iter self) -> Self::Iter<'iter>; +} + +trait CollectionFamily { + type Member: Collection; +} + +struct VecFamily; + +impl CollectionFamily for VecFamily { + type Member = Vec; +} + +impl Collection for Vec { + type Iter<'iter> where T: 'iter = std::slice::Iter<'iter, T>; + type Family = VecFamily; + + fn empty() -> Self { + Vec::new() + } + + fn add(&mut self, value: T) { + self.push(value) + } + + fn iterate<'iter>(&'iter self) -> Self::Iter<'iter> { + self.iter() + } +} + +fn floatify_sibling(ints: &C) -> >::Sibling +where + C: Collection, +{ + let mut res = ::Member::::empty(); + for &v in ints.iterate() { + res.add(v as f32); + } + res + //~^ ERROR mismatched types +} + +fn use_floatify() { + let a = vec![1i32, 2, 3]; + let c = floatify_sibling(&a); + assert_eq!(Some(&1.0), c.iterate().next()); +} + +fn main() { + use_floatify(); +} diff --git a/src/test/ui/generic-associated-types/collections-project-default.stderr b/src/test/ui/generic-associated-types/collections-project-default.stderr new file mode 100644 index 0000000000000..ca02b2603ba64 --- /dev/null +++ b/src/test/ui/generic-associated-types/collections-project-default.stderr @@ -0,0 +1,15 @@ +error[E0308]: mismatched types + --> $DIR/collections-project-default.rs:60:5 + | +LL | fn floatify_sibling(ints: &C) -> >::Sibling + | ------------------------------------ expected `>::Sibling` because of return type +... +LL | res + | ^^^ expected Collection::Sibling, found CollectionFamily::Member + | + = note: expected associated type `>::Sibling` + found associated type `<>::Family as CollectionFamily>::Member` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/generic-associated-types/collections.rs b/src/test/ui/generic-associated-types/collections.rs index 6f018f0401863..1b5b9c181fb61 100644 --- a/src/test/ui/generic-associated-types/collections.rs +++ b/src/test/ui/generic-associated-types/collections.rs @@ -6,13 +6,14 @@ // http://smallcultfollowing.com/babysteps/blog/2016/11/03/ // associated-type-constructors-part-2-family-traits/ +// run-pass + trait Collection { - type Iter<'iter>: Iterator; + type Iter<'iter>: Iterator where T: 'iter; type Family: CollectionFamily; // Test associated type defaults with parameters type Sibling: Collection = <>::Family as CollectionFamily>::Member; - //~^^ ERROR type-generic associated types are not yet implemented fn empty() -> Self; @@ -23,7 +24,6 @@ trait Collection { trait CollectionFamily { type Member: Collection; - //~^ ERROR type-generic associated types are not yet implemented } struct VecFamily; @@ -33,7 +33,7 @@ impl CollectionFamily for VecFamily { } impl Collection for Vec { - type Iter<'iter> = std::slice::Iter<'iter, T>; + type Iter<'iter> where T: 'iter = std::slice::Iter<'iter, T>; type Family = VecFamily; fn empty() -> Self { @@ -53,18 +53,7 @@ fn floatify(ints: &C) -> <>::Family as CollectionFamily> where C: Collection, { - let mut res = C::Family::Member::::empty(); - for &v in ints.iterate() { - res.add(v as f32); - } - res -} - -fn floatify_sibling(ints: &C) -> >::Sibling -where - C: Collection, -{ - let mut res = C::Family::Member::::empty(); + let mut res = ::Member::::empty(); for &v in ints.iterate() { res.add(v as f32); } @@ -72,11 +61,11 @@ where } fn use_floatify() { - let a = vec![1i32, 2, 3]; - let b = floatify(a); - println!("{}", b.iterate().next()); - let c = floatify_sibling(a); - println!("{}", c.iterate().next()); + let a = vec![1, 2, 3]; + let b = floatify(&a); + assert_eq!(Some(&1.0), b.iterate().next()); } -fn main() {} +fn main() { + use_floatify(); +} diff --git a/src/test/ui/generic-associated-types/collections.stderr b/src/test/ui/generic-associated-types/collections.stderr deleted file mode 100644 index fb06d5e49a391..0000000000000 --- a/src/test/ui/generic-associated-types/collections.stderr +++ /dev/null @@ -1,19 +0,0 @@ -error: type-generic associated types are not yet implemented - --> $DIR/collections.rs:13:5 - | -LL | / type Sibling: Collection = -LL | | <>::Family as CollectionFamily>::Member; - | |_________________________________________________________________________^ - | - = note: for more information, see issue #44265 for more information - -error: type-generic associated types are not yet implemented - --> $DIR/collections.rs:25:5 - | -LL | type Member: Collection; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: for more information, see issue #44265 for more information - -error: aborting due to 2 previous errors - diff --git a/src/test/ui/generic-associated-types/construct_with_other_type.rs b/src/test/ui/generic-associated-types/construct_with_other_type.rs index 2198b99db25c1..ff9d61658f4eb 100644 --- a/src/test/ui/generic-associated-types/construct_with_other_type.rs +++ b/src/test/ui/generic-associated-types/construct_with_other_type.rs @@ -1,7 +1,7 @@ #![allow(incomplete_features)] #![feature(generic_associated_types)] -// FIXME(#30472) normalize enough to handle this. +// check-pass use std::ops::Deref; @@ -17,7 +17,6 @@ trait Baz { } impl Baz for T where T: Foo { -//~^ ERROR type mismatch resolving type Quux<'a> where T: 'a = T; type Baa<'a> where T: 'a = &'a ::Bar<'a, 'static>; diff --git a/src/test/ui/generic-associated-types/construct_with_other_type.stderr b/src/test/ui/generic-associated-types/construct_with_other_type.stderr deleted file mode 100644 index b9468b3330b44..0000000000000 --- a/src/test/ui/generic-associated-types/construct_with_other_type.stderr +++ /dev/null @@ -1,18 +0,0 @@ -error[E0271]: type mismatch resolving `for<'a> <::Baa<'a> as std::ops::Deref>::Target == <::Quux<'a> as Foo>::Bar<'a, 'static>` - --> $DIR/construct_with_other_type.rs:19:9 - | -LL | impl Baz for T where T: Foo { - | - ^^^ expected type parameter `T`, found associated type - | | - | this type parameter - | - = note: expected associated type `::Bar<'_, 'static>` - found associated type `<::Quux<'_> as Foo>::Bar<'_, 'static>` -help: consider further restricting this bound - | -LL | impl Baz for T where T: Foo + Baz { - | ^^^^^^^^^^^^^^^ - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0271`. diff --git a/src/test/ui/generic-associated-types/gat-dont-ice-on-absent-feature-2.rs b/src/test/ui/generic-associated-types/gat-dont-ice-on-absent-feature-2.rs index f88df6a608aa3..c1d68812e9356 100644 --- a/src/test/ui/generic-associated-types/gat-dont-ice-on-absent-feature-2.rs +++ b/src/test/ui/generic-associated-types/gat-dont-ice-on-absent-feature-2.rs @@ -6,7 +6,6 @@ struct Foo; trait MyTrait { type Item; //~^ ERROR generic associated types are unstable [E0658] - //~| ERROR type-generic associated types are not yet implemented } impl MyTrait for Foo { diff --git a/src/test/ui/generic-associated-types/gat-dont-ice-on-absent-feature-2.stderr b/src/test/ui/generic-associated-types/gat-dont-ice-on-absent-feature-2.stderr index f3da27775adcf..34f536dbe8f64 100644 --- a/src/test/ui/generic-associated-types/gat-dont-ice-on-absent-feature-2.stderr +++ b/src/test/ui/generic-associated-types/gat-dont-ice-on-absent-feature-2.stderr @@ -8,7 +8,7 @@ LL | type Item; = help: add `#![feature(generic_associated_types)]` to the crate attributes to enable error[E0658]: generic associated types are unstable - --> $DIR/gat-dont-ice-on-absent-feature-2.rs:13:5 + --> $DIR/gat-dont-ice-on-absent-feature-2.rs:12:5 | LL | type Item = T; | ^^^^^^^^^^^^^^^^^ @@ -16,14 +16,6 @@ LL | type Item = T; = note: see issue #44265 for more information = help: add `#![feature(generic_associated_types)]` to the crate attributes to enable -error: type-generic associated types are not yet implemented - --> $DIR/gat-dont-ice-on-absent-feature-2.rs:7:5 - | -LL | type Item; - | ^^^^^^^^^^^^^ - | - = note: for more information, see issue #44265 for more information - -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/generic-associated-types/generic-associated-types-where.rs b/src/test/ui/generic-associated-types/generic-associated-types-where.rs index 589024e162166..1a94796535c14 100644 --- a/src/test/ui/generic-associated-types/generic-associated-types-where.rs +++ b/src/test/ui/generic-associated-types/generic-associated-types-where.rs @@ -9,11 +9,8 @@ use std::fmt::{Display, Debug}; trait Foo { type Assoc where Self: Sized; type Assoc2 where T: Display; - //~^ ERROR type-generic associated types are not yet implemented type Assoc3; - //~^ ERROR type-generic associated types are not yet implemented - type WithDefault<'a, T: Debug + 'a> = dyn Iterator; - //~^ ERROR type-generic associated types are not yet implemented + type WithDefault<'a, T: Debug + 'a>: ?Sized = dyn Iterator; type NoGenerics; } @@ -23,6 +20,7 @@ impl Foo for Bar { type Assoc = usize; type Assoc2 = Vec; type Assoc3 where T: Iterator = Vec; + //~^ impl has stricter requirements than trait type WithDefault<'a, T: Debug + 'a> = &'a dyn Iterator; type NoGenerics = ::std::cell::Cell; } diff --git a/src/test/ui/generic-associated-types/generic-associated-types-where.stderr b/src/test/ui/generic-associated-types/generic-associated-types-where.stderr index fb29b377a16e3..4d02f2c46a6d0 100644 --- a/src/test/ui/generic-associated-types/generic-associated-types-where.stderr +++ b/src/test/ui/generic-associated-types/generic-associated-types-where.stderr @@ -1,26 +1,12 @@ -error: type-generic associated types are not yet implemented - --> $DIR/generic-associated-types-where.rs:11:5 - | -LL | type Assoc2 where T: Display; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: for more information, see issue #44265 for more information - -error: type-generic associated types are not yet implemented - --> $DIR/generic-associated-types-where.rs:13:5 +error[E0276]: impl has stricter requirements than trait + --> $DIR/generic-associated-types-where.rs:22:5 | LL | type Assoc3; - | ^^^^^^^^^^^^^^^ - | - = note: for more information, see issue #44265 for more information - -error: type-generic associated types are not yet implemented - --> $DIR/generic-associated-types-where.rs:15:5 - | -LL | type WithDefault<'a, T: Debug + 'a> = dyn Iterator; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: for more information, see issue #44265 for more information + | --------------- definition of `Assoc3` from trait +... +LL | type Assoc3 where T: Iterator = Vec; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl has extra requirement `T: std::iter::Iterator` -error: aborting due to 3 previous errors +error: aborting due to previous error +For more information about this error, try `rustc --explain E0276`. diff --git a/src/test/ui/generic-associated-types/issue-47206-where-clause.rs b/src/test/ui/generic-associated-types/issue-47206-where-clause.rs index 53e350aacf88e..de2b978460f7f 100644 --- a/src/test/ui/generic-associated-types/issue-47206-where-clause.rs +++ b/src/test/ui/generic-associated-types/issue-47206-where-clause.rs @@ -5,13 +5,13 @@ trait Foo { type Assoc3; - //~^ type-generic associated types are not yet implemented } struct Bar; impl Foo for Bar { type Assoc3 where T: Iterator = Vec; + //~^ ERROR impl has stricter requirements than trait } fn main() {} diff --git a/src/test/ui/generic-associated-types/issue-47206-where-clause.stderr b/src/test/ui/generic-associated-types/issue-47206-where-clause.stderr index c9c1a4753b0dd..bc5c40ff029f9 100644 --- a/src/test/ui/generic-associated-types/issue-47206-where-clause.stderr +++ b/src/test/ui/generic-associated-types/issue-47206-where-clause.stderr @@ -1,10 +1,12 @@ -error: type-generic associated types are not yet implemented - --> $DIR/issue-47206-where-clause.rs:7:5 +error[E0276]: impl has stricter requirements than trait + --> $DIR/issue-47206-where-clause.rs:13:5 | LL | type Assoc3; - | ^^^^^^^^^^^^^^^ - | - = note: for more information, see issue #44265 for more information + | --------------- definition of `Assoc3` from trait +... +LL | type Assoc3 where T: Iterator = Vec; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl has extra requirement `T: std::iter::Iterator` error: aborting due to previous error +For more information about this error, try `rustc --explain E0276`. diff --git a/src/test/ui/generic-associated-types/issue-62326-parameter-out-of-range.rs b/src/test/ui/generic-associated-types/issue-62326-parameter-out-of-range.rs index 1a79dbf2279a0..404be59a36d92 100644 --- a/src/test/ui/generic-associated-types/issue-62326-parameter-out-of-range.rs +++ b/src/test/ui/generic-associated-types/issue-62326-parameter-out-of-range.rs @@ -1,11 +1,14 @@ #![allow(incomplete_features)] #![feature(generic_associated_types)] -// FIXME(generic-associated-types) Investigate why this doesn't compile. +// check-pass trait Iterator { type Item<'a>: 'a; - //~^ ERROR the requirement `for<'a> ::Item<'a>: 'a` is not satisfied +} + +impl Iterator for () { + type Item<'a> = &'a (); } fn main() {} diff --git a/src/test/ui/generic-associated-types/issue-62326-parameter-out-of-range.stderr b/src/test/ui/generic-associated-types/issue-62326-parameter-out-of-range.stderr deleted file mode 100644 index 4b06baa09ffbf..0000000000000 --- a/src/test/ui/generic-associated-types/issue-62326-parameter-out-of-range.stderr +++ /dev/null @@ -1,10 +0,0 @@ -error[E0280]: the requirement `for<'a> ::Item<'a>: 'a` is not satisfied - --> $DIR/issue-62326-parameter-out-of-range.rs:7:20 - | -LL | trait Iterator { - | -------- required by a bound in this -LL | type Item<'a>: 'a; - | ^^ required by this bound in `Iterator` - -error: aborting due to previous error - diff --git a/src/test/ui/generic-associated-types/issue-67424.rs b/src/test/ui/generic-associated-types/issue-67424.rs index 9b616b8abc2ee..fa35a3e8b04d1 100644 --- a/src/test/ui/generic-associated-types/issue-67424.rs +++ b/src/test/ui/generic-associated-types/issue-67424.rs @@ -7,7 +7,6 @@ trait Trait1 { trait Trait2 { type Type1: Trait1; //~^ ERROR: generic associated types are unstable - //~| ERROR: type-generic associated types are not yet implemented } fn main() {} diff --git a/src/test/ui/generic-associated-types/issue-67424.stderr b/src/test/ui/generic-associated-types/issue-67424.stderr index 8b08c71759bb9..bbb7d56f5928e 100644 --- a/src/test/ui/generic-associated-types/issue-67424.stderr +++ b/src/test/ui/generic-associated-types/issue-67424.stderr @@ -7,14 +7,6 @@ LL | type Type1: Trait1; = note: see issue #44265 for more information = help: add `#![feature(generic_associated_types)]` to the crate attributes to enable -error: type-generic associated types are not yet implemented - --> $DIR/issue-67424.rs:8:5 - | -LL | type Type1: Trait1; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: for more information, see issue #44265 for more information - -error: aborting due to 2 previous errors +error: aborting due to previous error For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/generic-associated-types/issue-68641-check-gat-bounds.rs b/src/test/ui/generic-associated-types/issue-68641-check-gat-bounds.rs new file mode 100644 index 0000000000000..71f9b2967dc58 --- /dev/null +++ b/src/test/ui/generic-associated-types/issue-68641-check-gat-bounds.rs @@ -0,0 +1,32 @@ +// Regression test for #68641 + +#![feature(generic_associated_types)] +//~^ WARNING the feature `generic_associated_types` is incomplete and may not + +trait UnsafeCopy { + type Item<'a>: Copy; + + fn copy<'a>(item: &Self::Item<'a>) -> Self::Item<'a> { + *item + } +} + +impl UnsafeCopy for T { + type Item<'a> = T; + //~^ ERROR the trait bound `T: std::marker::Copy` is not satisfied +} + +fn main() { + let mut s = String::from("Hello world!"); + + let copy = String::copy(&s); + + // Do we indeed point to the samme memory? + assert!(s.as_ptr() == copy.as_ptr()); + + // Any use of `copy` is certeinly UB after this + drop(s); + + // UB UB UB UB UB!! + println!("{}", copy); +} diff --git a/src/test/ui/generic-associated-types/issue-68641-check-gat-bounds.stderr b/src/test/ui/generic-associated-types/issue-68641-check-gat-bounds.stderr new file mode 100644 index 0000000000000..834bc3b7878f2 --- /dev/null +++ b/src/test/ui/generic-associated-types/issue-68641-check-gat-bounds.stderr @@ -0,0 +1,26 @@ +warning: the feature `generic_associated_types` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/issue-68641-check-gat-bounds.rs:3:12 + | +LL | #![feature(generic_associated_types)] + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #44265 for more information + +error[E0277]: the trait bound `T: std::marker::Copy` is not satisfied + --> $DIR/issue-68641-check-gat-bounds.rs:15:5 + | +LL | type Item<'a>: Copy; + | -------------------- required by `UnsafeCopy::Item` +... +LL | type Item<'a> = T; + | ^^^^^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `T` + | +help: consider restricting type parameter `T` + | +LL | impl UnsafeCopy for T { + | ^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error; 1 warning emitted + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/generic-associated-types/issue-68642-broken-llvm-ir.rs b/src/test/ui/generic-associated-types/issue-68642-broken-llvm-ir.rs new file mode 100644 index 0000000000000..c99073c13284d --- /dev/null +++ b/src/test/ui/generic-associated-types/issue-68642-broken-llvm-ir.rs @@ -0,0 +1,21 @@ +// Regression test for #68642 + +#![feature(generic_associated_types)] +//~^ WARNING the feature `generic_associated_types` is incomplete and may not + +trait Fun { + type F<'a>: Fn() -> u32; + + fn callme<'a>(f: Self::F<'a>) -> u32 { + f() + } +} + +impl Fun for T { + type F<'a> = Self; + //~^ ERROR expected a `std::ops::Fn<()>` closure, found `T` +} + +fn main() { + usize>::callme(|| 1); +} diff --git a/src/test/ui/generic-associated-types/issue-68642-broken-llvm-ir.stderr b/src/test/ui/generic-associated-types/issue-68642-broken-llvm-ir.stderr new file mode 100644 index 0000000000000..89cc5dfd06018 --- /dev/null +++ b/src/test/ui/generic-associated-types/issue-68642-broken-llvm-ir.stderr @@ -0,0 +1,28 @@ +warning: the feature `generic_associated_types` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/issue-68642-broken-llvm-ir.rs:3:12 + | +LL | #![feature(generic_associated_types)] + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #44265 for more information + +error[E0277]: expected a `std::ops::Fn<()>` closure, found `T` + --> $DIR/issue-68642-broken-llvm-ir.rs:15:5 + | +LL | type F<'a>: Fn() -> u32; + | ------------------------ required by `Fun::F` +... +LL | type F<'a> = Self; + | ^^^^^^^^^^^^^^^^^^ expected an `Fn<()>` closure, found `T` + | + = help: the trait `std::ops::Fn<()>` is not implemented for `T` + = note: wrap the `T` in a closure with no arguments: `|| { /* code */ } +help: consider restricting type parameter `T` + | +LL | impl> Fun for T { + | ^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error; 1 warning emitted + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/generic-associated-types/issue-68643-broken-mir.rs b/src/test/ui/generic-associated-types/issue-68643-broken-mir.rs new file mode 100644 index 0000000000000..24133e75cccee --- /dev/null +++ b/src/test/ui/generic-associated-types/issue-68643-broken-mir.rs @@ -0,0 +1,21 @@ +// Regression test for #68643 + +#![feature(generic_associated_types)] +//~^ WARNING the feature `generic_associated_types` is incomplete and may not + +trait Fun { + type F<'a>: Fn() -> u32; + + fn callme<'a>(f: Self::F<'a>) -> u32 { + f() + } +} + +impl Fun for T { + type F<'a> = Self; + //~^ ERROR expected a `std::ops::Fn<()>` closure, found `T` +} + +pub fn main() { + ::callme(|| {}); +} diff --git a/src/test/ui/generic-associated-types/issue-68643-broken-mir.stderr b/src/test/ui/generic-associated-types/issue-68643-broken-mir.stderr new file mode 100644 index 0000000000000..efd3287853f03 --- /dev/null +++ b/src/test/ui/generic-associated-types/issue-68643-broken-mir.stderr @@ -0,0 +1,28 @@ +warning: the feature `generic_associated_types` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/issue-68643-broken-mir.rs:3:12 + | +LL | #![feature(generic_associated_types)] + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #44265 for more information + +error[E0277]: expected a `std::ops::Fn<()>` closure, found `T` + --> $DIR/issue-68643-broken-mir.rs:15:5 + | +LL | type F<'a>: Fn() -> u32; + | ------------------------ required by `Fun::F` +... +LL | type F<'a> = Self; + | ^^^^^^^^^^^^^^^^^^ expected an `Fn<()>` closure, found `T` + | + = help: the trait `std::ops::Fn<()>` is not implemented for `T` + = note: wrap the `T` in a closure with no arguments: `|| { /* code */ } +help: consider restricting type parameter `T` + | +LL | impl> Fun for T { + | ^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error; 1 warning emitted + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/generic-associated-types/issue-68644-codegen-selection.rs b/src/test/ui/generic-associated-types/issue-68644-codegen-selection.rs new file mode 100644 index 0000000000000..22620c61b8390 --- /dev/null +++ b/src/test/ui/generic-associated-types/issue-68644-codegen-selection.rs @@ -0,0 +1,21 @@ +// Regression test for #68644 + +#![feature(generic_associated_types)] +//~^ WARNING the feature `generic_associated_types` is incomplete and may not + +trait Fun { + type F<'a>: Fn() -> u32; + + fn callme<'a>(f: Self::F<'a>) -> u32 { + f() + } +} + +impl Fun for T { + type F<'a> = Self; + //~^ ERROR expected a `std::ops::Fn<()>` closure, found `T` +} + +fn main() { + ::callme(0); +} diff --git a/src/test/ui/generic-associated-types/issue-68644-codegen-selection.stderr b/src/test/ui/generic-associated-types/issue-68644-codegen-selection.stderr new file mode 100644 index 0000000000000..5da924a512f00 --- /dev/null +++ b/src/test/ui/generic-associated-types/issue-68644-codegen-selection.stderr @@ -0,0 +1,28 @@ +warning: the feature `generic_associated_types` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/issue-68644-codegen-selection.rs:3:12 + | +LL | #![feature(generic_associated_types)] + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #44265 for more information + +error[E0277]: expected a `std::ops::Fn<()>` closure, found `T` + --> $DIR/issue-68644-codegen-selection.rs:15:5 + | +LL | type F<'a>: Fn() -> u32; + | ------------------------ required by `Fun::F` +... +LL | type F<'a> = Self; + | ^^^^^^^^^^^^^^^^^^ expected an `Fn<()>` closure, found `T` + | + = help: the trait `std::ops::Fn<()>` is not implemented for `T` + = note: wrap the `T` in a closure with no arguments: `|| { /* code */ } +help: consider restricting type parameter `T` + | +LL | impl> Fun for T { + | ^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error; 1 warning emitted + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/generic-associated-types/issue-68645-codegen-fulfillment.rs b/src/test/ui/generic-associated-types/issue-68645-codegen-fulfillment.rs new file mode 100644 index 0000000000000..423b80e8476f4 --- /dev/null +++ b/src/test/ui/generic-associated-types/issue-68645-codegen-fulfillment.rs @@ -0,0 +1,21 @@ +// Regression test for #68645 + +#![feature(generic_associated_types)] +//~^ WARNING the feature `generic_associated_types` is incomplete and may not + +trait Fun { + type F<'a>: Fn() -> u32; + + fn callme<'a>(f: Self::F<'a>) -> u32 { + f() + } +} + +impl Fun for T { + type F<'a> = Self; + //~^ ERROR expected a `std::ops::Fn<()>` closure, found `T` +} + +fn main() { + <&dyn Iterator>::callme(&std::iter::once(1)); +} diff --git a/src/test/ui/generic-associated-types/issue-68645-codegen-fulfillment.stderr b/src/test/ui/generic-associated-types/issue-68645-codegen-fulfillment.stderr new file mode 100644 index 0000000000000..12d84ab6a369b --- /dev/null +++ b/src/test/ui/generic-associated-types/issue-68645-codegen-fulfillment.stderr @@ -0,0 +1,28 @@ +warning: the feature `generic_associated_types` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/issue-68645-codegen-fulfillment.rs:3:12 + | +LL | #![feature(generic_associated_types)] + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #44265 for more information + +error[E0277]: expected a `std::ops::Fn<()>` closure, found `T` + --> $DIR/issue-68645-codegen-fulfillment.rs:15:5 + | +LL | type F<'a>: Fn() -> u32; + | ------------------------ required by `Fun::F` +... +LL | type F<'a> = Self; + | ^^^^^^^^^^^^^^^^^^ expected an `Fn<()>` closure, found `T` + | + = help: the trait `std::ops::Fn<()>` is not implemented for `T` + = note: wrap the `T` in a closure with no arguments: `|| { /* code */ } +help: consider restricting type parameter `T` + | +LL | impl> Fun for T { + | ^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error; 1 warning emitted + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/generic-associated-types/issue-68656-unsized-values.rs b/src/test/ui/generic-associated-types/issue-68656-unsized-values.rs new file mode 100644 index 0000000000000..4ccd42ba6432d --- /dev/null +++ b/src/test/ui/generic-associated-types/issue-68656-unsized-values.rs @@ -0,0 +1,22 @@ +// Regression test for #68656 + +#![feature(generic_associated_types)] +//~^ WARNING the feature `generic_associated_types` is incomplete and may not + +trait UnsafeCopy { + type Item<'a>: std::ops::Deref; + + fn bug<'a>(item: &Self::Item<'a>) -> () { + let x: T = **item; + &x as *const _; + } +} + +impl UnsafeCopy for T { + type Item<'a> = T; + //~^ ERROR type mismatch resolving `::Target == T` +} + +fn main() { + <&'static str>::bug(&""); +} diff --git a/src/test/ui/generic-associated-types/issue-68656-unsized-values.stderr b/src/test/ui/generic-associated-types/issue-68656-unsized-values.stderr new file mode 100644 index 0000000000000..e1ceeac3196a8 --- /dev/null +++ b/src/test/ui/generic-associated-types/issue-68656-unsized-values.stderr @@ -0,0 +1,30 @@ +warning: the feature `generic_associated_types` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/issue-68656-unsized-values.rs:3:12 + | +LL | #![feature(generic_associated_types)] + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #44265 for more information + +error[E0271]: type mismatch resolving `::Target == T` + --> $DIR/issue-68656-unsized-values.rs:16:5 + | +LL | type Item<'a>: std::ops::Deref; + | ------------------------------------------- required by `UnsafeCopy::Item` +... +LL | impl UnsafeCopy for T { + | - this type parameter +LL | type Item<'a> = T; + | ^^^^^^^^^^^^^^^^^^ expected type parameter `T`, found associated type + | + = note: expected type parameter `T` + found associated type `::Target` +help: consider further restricting this bound + | +LL | impl> UnsafeCopy for T { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error; 1 warning emitted + +For more information about this error, try `rustc --explain E0271`. diff --git a/src/test/ui/generic-associated-types/iterable.rs b/src/test/ui/generic-associated-types/iterable.rs index 105ab4a8adc38..600a69006c1ea 100644 --- a/src/test/ui/generic-associated-types/iterable.rs +++ b/src/test/ui/generic-associated-types/iterable.rs @@ -1,7 +1,7 @@ #![allow(incomplete_features)] #![feature(generic_associated_types)] -// FIXME(#30472) normalize enough to handle this. +// run-pass trait Iterable { type Item<'a> where Self: 'a; @@ -13,39 +13,35 @@ trait Iterable { // Impl for struct type impl Iterable for Vec { type Item<'a> where T: 'a = as Iterator>::Item; - //~^ ERROR type mismatch resolving type Iter<'a> where T: 'a = std::slice::Iter<'a, T>; fn iter<'a>(&'a self) -> Self::Iter<'a> { - //~^ ERROR type mismatch resolving - self.iter() + self[..].iter() } } // Impl for a primitive type impl Iterable for [T] { type Item<'a> where T: 'a = as Iterator>::Item; - //~^ ERROR type mismatch resolving type Iter<'a> where T: 'a = std::slice::Iter<'a, T>; fn iter<'a>(&'a self) -> Self::Iter<'a> { - //~^ ERROR type mismatch resolving self.iter() } } -fn make_iter<'a, I: Iterable>(it: &'a I) -> I::Iter<'a> { +fn make_iter<'a, I: Iterable + ?Sized>(it: &'a I) -> I::Iter<'a> { it.iter() } -fn get_first<'a, I: Iterable>(it: &'a I) -> Option> { +fn get_first<'a, I: Iterable + ?Sized>(it: &'a I) -> Option> { it.iter().next() } fn main() { let v = vec![1, 2, 3]; - assert_eq!(v, make_iter(&v).copied().collect()); - assert_eq!(v, make_iter(&*v).copied().collect()); - assert_eq!(1, get_first(&v)); - assert_eq!(1, get_first(&*v)); + assert_eq!(v, make_iter(&v).copied().collect::>()); + assert_eq!(v, make_iter(&*v).copied().collect::>()); + assert_eq!(Some(&1), get_first(&v)); + assert_eq!(Some(&1), get_first(&*v)); } diff --git a/src/test/ui/generic-associated-types/iterable.stderr b/src/test/ui/generic-associated-types/iterable.stderr deleted file mode 100644 index 6e75462122513..0000000000000 --- a/src/test/ui/generic-associated-types/iterable.stderr +++ /dev/null @@ -1,59 +0,0 @@ -error[E0271]: type mismatch resolving `for<'a> < as Iterable>::Iter<'a> as std::iter::Iterator>::Item == as Iterable>::Item<'a>` - --> $DIR/iterable.rs:15:33 - | -LL | type Item<'a> where T: 'a = as Iterator>::Item; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected reference, found associated type - | - = note: expected reference `&T` - found associated type ` as Iterable>::Item<'_>` - = help: consider constraining the associated type ` as Iterable>::Item<'_>` to `&_` - = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html - -error[E0271]: type mismatch resolving `for<'a> <<[T] as Iterable>::Iter<'a> as std::iter::Iterator>::Item == <[T] as Iterable>::Item<'a>` - --> $DIR/iterable.rs:27:33 - | -LL | type Item<'a> where T: 'a = as Iterator>::Item; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected reference, found associated type - | - = note: expected reference `&T` - found associated type `<[T] as Iterable>::Item<'_>` - = help: consider constraining the associated type `<[T] as Iterable>::Item<'_>` to `&_` - = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html - -error[E0271]: type mismatch resolving `for<'a> < as Iterable>::Iter<'a> as std::iter::Iterator>::Item == as Iterable>::Item<'a>` - --> $DIR/iterable.rs:19:30 - | -LL | trait Iterable { - | -------- required by a bound in this -LL | type Item<'a> where Self: 'a; -LL | type Iter<'a>: Iterator> where Self: 'a; - | --------------------- required by this bound in `Iterable` -... -LL | fn iter<'a>(&'a self) -> Self::Iter<'a> { - | ^^^^^^^^^^^^^^ expected associated type, found reference - | - = note: expected associated type ` as Iterable>::Item<'_>` - found reference `&T` - = help: consider constraining the associated type ` as Iterable>::Item<'_>` to `&_` or calling a method that returns ` as Iterable>::Item<'_>` - = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html - -error[E0271]: type mismatch resolving `for<'a> <<[T] as Iterable>::Iter<'a> as std::iter::Iterator>::Item == <[T] as Iterable>::Item<'a>` - --> $DIR/iterable.rs:31:30 - | -LL | trait Iterable { - | -------- required by a bound in this -LL | type Item<'a> where Self: 'a; -LL | type Iter<'a>: Iterator> where Self: 'a; - | --------------------- required by this bound in `Iterable` -... -LL | fn iter<'a>(&'a self) -> Self::Iter<'a> { - | ^^^^^^^^^^^^^^ expected associated type, found reference - | - = note: expected associated type `<[T] as Iterable>::Item<'_>` - found reference `&T` - = help: consider constraining the associated type `<[T] as Iterable>::Item<'_>` to `&_` or calling a method that returns `<[T] as Iterable>::Item<'_>` - = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html - -error: aborting due to 4 previous errors - -For more information about this error, try `rustc --explain E0271`. diff --git a/src/test/ui/generic-associated-types/missing-bounds.fixed b/src/test/ui/generic-associated-types/missing-bounds.fixed index 364d2388741b0..3ba7d043d0759 100644 --- a/src/test/ui/generic-associated-types/missing-bounds.fixed +++ b/src/test/ui/generic-associated-types/missing-bounds.fixed @@ -34,12 +34,11 @@ impl> Add for D { struct E(B); -impl Add for E where B: Add, B: std::ops::Add { - //~^ ERROR equality constraints are not yet supported in `where` clauses +impl Add for E where B: Add { type Output = Self; fn add(self, rhs: Self) -> Self { - Self(self.0 + rhs.0) //~ ERROR mismatched types + Self(self.0 + rhs.0) } } diff --git a/src/test/ui/generic-associated-types/missing-bounds.rs b/src/test/ui/generic-associated-types/missing-bounds.rs index ffafff5e9f586..962d2db9476bd 100644 --- a/src/test/ui/generic-associated-types/missing-bounds.rs +++ b/src/test/ui/generic-associated-types/missing-bounds.rs @@ -34,12 +34,11 @@ impl Add for D { struct E(B); -impl Add for E where ::Output = B { - //~^ ERROR equality constraints are not yet supported in `where` clauses +impl Add for E where B: Add { type Output = Self; fn add(self, rhs: Self) -> Self { - Self(self.0 + rhs.0) //~ ERROR mismatched types + Self(self.0 + rhs.0) } } diff --git a/src/test/ui/generic-associated-types/missing-bounds.stderr b/src/test/ui/generic-associated-types/missing-bounds.stderr index 50536fdaca96e..630ceac093ef2 100644 --- a/src/test/ui/generic-associated-types/missing-bounds.stderr +++ b/src/test/ui/generic-associated-types/missing-bounds.stderr @@ -1,15 +1,3 @@ -error: equality constraints are not yet supported in `where` clauses - --> $DIR/missing-bounds.rs:37:33 - | -LL | impl Add for E where ::Output = B { - | ^^^^^^^^^^^^^^^^^^^^^^ not supported - | - = note: see issue #20041 for more information -help: if `Output` is an associated type you're trying to set, use the associated type binding syntax - | -LL | impl Add for E where B: Add { - | ^^^^^^^^^^^^^^^^^^ - error[E0308]: mismatched types --> $DIR/missing-bounds.rs:11:11 | @@ -55,23 +43,7 @@ help: consider restricting type parameter `B` LL | impl> Add for D { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0308]: mismatched types - --> $DIR/missing-bounds.rs:42:14 - | -LL | impl Add for E where ::Output = B { - | - this type parameter -... -LL | Self(self.0 + rhs.0) - | ^^^^^^^^^^^^^^ expected type parameter `B`, found associated type - | - = note: expected type parameter `B` - found associated type `::Output` -help: consider further restricting type parameter `B` - | -LL | impl Add for E where ::Output = B, B: std::ops::Add { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: aborting due to 5 previous errors +error: aborting due to 3 previous errors Some errors have detailed explanations: E0308, E0369. For more information about an error, try `rustc --explain E0308`. diff --git a/src/test/ui/generic-associated-types/parameter_number_and_kind.rs b/src/test/ui/generic-associated-types/parameter_number_and_kind.rs index 0edc5c48c01af..f4d09fc1539da 100644 --- a/src/test/ui/generic-associated-types/parameter_number_and_kind.rs +++ b/src/test/ui/generic-associated-types/parameter_number_and_kind.rs @@ -7,18 +7,14 @@ trait Foo { type B<'a, 'b>; type C; type D; - //~^ ERROR type-generic associated types are not yet implemented type E<'a, T>; - //~^ ERROR type-generic associated types are not yet implemented // Test parameters in default values type FOk = Self::E<'static, T>; - //~^ ERROR type-generic associated types are not yet implemented type FErr1 = Self::E<'static, 'static>; //~^ ERROR wrong number of lifetime arguments: expected 1, found 2 //~| ERROR wrong number of type arguments: expected 1, found 0 type FErr2 = Self::E<'static, T, u32>; - //~^ ERROR type-generic associated types are not yet implemented - //~| ERROR wrong number of type arguments: expected 1, found 2 + //~^ ERROR wrong number of type arguments: expected 1, found 2 } fn main() {} diff --git a/src/test/ui/generic-associated-types/parameter_number_and_kind.stderr b/src/test/ui/generic-associated-types/parameter_number_and_kind.stderr index 028ab72f48812..ed090e302cefa 100644 --- a/src/test/ui/generic-associated-types/parameter_number_and_kind.stderr +++ b/src/test/ui/generic-associated-types/parameter_number_and_kind.stderr @@ -1,53 +1,21 @@ -error: type-generic associated types are not yet implemented - --> $DIR/parameter_number_and_kind.rs:9:5 - | -LL | type D; - | ^^^^^^^^^^ - | - = note: for more information, see issue #44265 for more information - -error: type-generic associated types are not yet implemented - --> $DIR/parameter_number_and_kind.rs:11:5 - | -LL | type E<'a, T>; - | ^^^^^^^^^^^^^^ - | - = note: for more information, see issue #44265 for more information - -error: type-generic associated types are not yet implemented - --> $DIR/parameter_number_and_kind.rs:14:5 - | -LL | type FOk = Self::E<'static, T>; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: for more information, see issue #44265 for more information - -error: type-generic associated types are not yet implemented - --> $DIR/parameter_number_and_kind.rs:19:5 - | -LL | type FErr2 = Self::E<'static, T, u32>; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: for more information, see issue #44265 for more information - error[E0107]: wrong number of lifetime arguments: expected 1, found 2 - --> $DIR/parameter_number_and_kind.rs:16:35 + --> $DIR/parameter_number_and_kind.rs:13:35 | LL | type FErr1 = Self::E<'static, 'static>; | ^^^^^^^ unexpected lifetime argument error[E0107]: wrong number of type arguments: expected 1, found 0 - --> $DIR/parameter_number_and_kind.rs:16:18 + --> $DIR/parameter_number_and_kind.rs:13:18 | LL | type FErr1 = Self::E<'static, 'static>; | ^^^^^^^^^^^^^^^^^^^^^^^^^ expected 1 type argument error[E0107]: wrong number of type arguments: expected 1, found 2 - --> $DIR/parameter_number_and_kind.rs:19:41 + --> $DIR/parameter_number_and_kind.rs:16:41 | LL | type FErr2 = Self::E<'static, T, u32>; | ^^^ unexpected type argument -error: aborting due to 7 previous errors +error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0107`. diff --git a/src/test/ui/generic-associated-types/pointer_family.rs b/src/test/ui/generic-associated-types/pointer_family.rs index 1668759b4e39c..b322b752a1567 100644 --- a/src/test/ui/generic-associated-types/pointer_family.rs +++ b/src/test/ui/generic-associated-types/pointer_family.rs @@ -1,7 +1,7 @@ #![allow(incomplete_features)] #![feature(generic_associated_types)] -// FIXME(#44265): allow type-generic associated types. +// check-pass use std::rc::Rc; use std::sync::Arc; @@ -9,7 +9,6 @@ use std::ops::Deref; trait PointerFamily { type Pointer: Deref; - //~^ ERROR type-generic associated types are not yet implemented fn new(value: T) -> Self::Pointer; } diff --git a/src/test/ui/generic-associated-types/pointer_family.stderr b/src/test/ui/generic-associated-types/pointer_family.stderr deleted file mode 100644 index 83fe992fcb571..0000000000000 --- a/src/test/ui/generic-associated-types/pointer_family.stderr +++ /dev/null @@ -1,10 +0,0 @@ -error: type-generic associated types are not yet implemented - --> $DIR/pointer_family.rs:11:5 - | -LL | type Pointer: Deref; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: for more information, see issue #44265 for more information - -error: aborting due to previous error - diff --git a/src/test/ui/generic-associated-types/shadowing.rs b/src/test/ui/generic-associated-types/shadowing.rs index 5c308948bd3f8..44528ca1da36e 100644 --- a/src/test/ui/generic-associated-types/shadowing.rs +++ b/src/test/ui/generic-associated-types/shadowing.rs @@ -18,12 +18,10 @@ impl<'a> NoShadow<'a> for &'a u32 { trait ShadowT { type Bar; //~^ ERROR the name `T` is already used - //~| ERROR type-generic associated types are not yet implemented } trait NoShadowT { type Bar; // OK - //~^ ERROR type-generic associated types are not yet implemented } impl NoShadowT for Option { diff --git a/src/test/ui/generic-associated-types/shadowing.stderr b/src/test/ui/generic-associated-types/shadowing.stderr index 2d9a0d6fceb2d..d51c29080a0c9 100644 --- a/src/test/ui/generic-associated-types/shadowing.stderr +++ b/src/test/ui/generic-associated-types/shadowing.stderr @@ -7,7 +7,7 @@ LL | type Bar; | ^ already used error[E0403]: the name `T` is already used for a generic parameter in this item's generic parameters - --> $DIR/shadowing.rs:30:14 + --> $DIR/shadowing.rs:28:14 | LL | impl NoShadowT for Option { | - first use of `T` @@ -30,23 +30,7 @@ LL | impl<'a> NoShadow<'a> for &'a u32 { LL | type Bar<'a> = i32; | ^^ lifetime 'a already in scope -error: type-generic associated types are not yet implemented - --> $DIR/shadowing.rs:19:5 - | -LL | type Bar; - | ^^^^^^^^^^^^ - | - = note: for more information, see issue #44265 for more information - -error: type-generic associated types are not yet implemented - --> $DIR/shadowing.rs:25:5 - | -LL | type Bar; // OK - | ^^^^^^^^^^^^ - | - = note: for more information, see issue #44265 for more information - -error: aborting due to 6 previous errors +error: aborting due to 4 previous errors Some errors have detailed explanations: E0403, E0496. For more information about an error, try `rustc --explain E0403`. diff --git a/src/test/ui/generic-associated-types/unsatisfied-outlives-bound.rs b/src/test/ui/generic-associated-types/unsatisfied-outlives-bound.rs new file mode 100644 index 0000000000000..7510c58d57489 --- /dev/null +++ b/src/test/ui/generic-associated-types/unsatisfied-outlives-bound.rs @@ -0,0 +1,22 @@ +#![allow(incomplete_features)] +#![feature(generic_associated_types)] + +trait ATy { + type Item<'a>: 'a; +} + +impl<'b> ATy for &'b () { + type Item<'a> = &'b (); + //~^ ERROR does not fulfill the required lifetime +} + +trait StaticTy { + type Item<'a>: 'static; +} + +impl StaticTy for () { + type Item<'a> = &'a (); + //~^ ERROR does not fulfill the required lifetime +} + +fn main() {} diff --git a/src/test/ui/generic-associated-types/unsatisfied-outlives-bound.stderr b/src/test/ui/generic-associated-types/unsatisfied-outlives-bound.stderr new file mode 100644 index 0000000000000..5d612284a2187 --- /dev/null +++ b/src/test/ui/generic-associated-types/unsatisfied-outlives-bound.stderr @@ -0,0 +1,23 @@ +error[E0477]: the type `&'b ()` does not fulfill the required lifetime + --> $DIR/unsatisfied-outlives-bound.rs:9:5 + | +LL | type Item<'a> = &'b (); + | ^^^^^^^^^^^^^^^^^^^^^^^ + | +note: type must outlive the lifetime `'a` as defined on the associated item at 9:15 + --> $DIR/unsatisfied-outlives-bound.rs:9:15 + | +LL | type Item<'a> = &'b (); + | ^^ + +error[E0477]: the type `&'a ()` does not fulfill the required lifetime + --> $DIR/unsatisfied-outlives-bound.rs:18:5 + | +LL | type Item<'a> = &'a (); + | ^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: type must satisfy the static lifetime + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0477`. diff --git a/src/test/ui/issues/issue-38091.rs b/src/test/ui/issues/issue-38091.rs index c126243050244..a84391b94d1de 100644 --- a/src/test/ui/issues/issue-38091.rs +++ b/src/test/ui/issues/issue-38091.rs @@ -1,4 +1,3 @@ -// run-pass #![feature(specialization)] //~^ WARN the feature `specialization` is incomplete @@ -8,6 +7,7 @@ trait Iterate<'a> { } impl<'a, T> Iterate<'a> for T where T: Check { default type Ty = (); + //~^ ERROR the trait bound `(): Valid` is not satisfied default fn iterate(self) {} } diff --git a/src/test/ui/issues/issue-38091.stderr b/src/test/ui/issues/issue-38091.stderr index a9855445f6668..81beec8026314 100644 --- a/src/test/ui/issues/issue-38091.stderr +++ b/src/test/ui/issues/issue-38091.stderr @@ -1,5 +1,5 @@ warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/issue-38091.rs:2:12 + --> $DIR/issue-38091.rs:1:12 | LL | #![feature(specialization)] | ^^^^^^^^^^^^^^ @@ -7,5 +7,15 @@ LL | #![feature(specialization)] = note: `#[warn(incomplete_features)]` on by default = note: see issue #31844 for more information -warning: 1 warning emitted +error[E0277]: the trait bound `(): Valid` is not satisfied + --> $DIR/issue-38091.rs:9:5 + | +LL | type Ty: Valid; + | --------------- required by `Iterate::Ty` +... +LL | default type Ty = (); + | ^^^^^^^^^^^^^^^^^^^^^ the trait `Valid` is not implemented for `()` + +error: aborting due to previous error; 1 warning emitted +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/lint/lint-ctypes-73251-1.rs b/src/test/ui/lint/lint-ctypes-73251-1.rs new file mode 100644 index 0000000000000..2ce80982f5ca1 --- /dev/null +++ b/src/test/ui/lint/lint-ctypes-73251-1.rs @@ -0,0 +1,24 @@ +#![feature(type_alias_impl_trait)] +#![deny(improper_ctypes)] + +pub trait Baz { } + +impl Baz for u32 { } + +type Qux = impl Baz; + +pub trait Foo { + type Assoc; +} + +impl Foo for u32 { + type Assoc = Qux; +} + +fn assign() -> Qux { 1 } + +extern "C" { + pub fn lint_me() -> ::Assoc; //~ ERROR: uses type `impl Baz` +} + +fn main() {} diff --git a/src/test/ui/lint/lint-ctypes-73251-1.stderr b/src/test/ui/lint/lint-ctypes-73251-1.stderr new file mode 100644 index 0000000000000..0b4237bb96fb7 --- /dev/null +++ b/src/test/ui/lint/lint-ctypes-73251-1.stderr @@ -0,0 +1,15 @@ +error: `extern` block uses type `impl Baz`, which is not FFI-safe + --> $DIR/lint-ctypes-73251-1.rs:21:25 + | +LL | pub fn lint_me() -> ::Assoc; + | ^^^^^^^^^^^^^^^^^^^ not FFI-safe + | +note: the lint level is defined here + --> $DIR/lint-ctypes-73251-1.rs:2:9 + | +LL | #![deny(improper_ctypes)] + | ^^^^^^^^^^^^^^^ + = note: opaque types have no C equivalent + +error: aborting due to previous error + diff --git a/src/test/ui/lint/lint-ctypes-73251-2.rs b/src/test/ui/lint/lint-ctypes-73251-2.rs new file mode 100644 index 0000000000000..3427c657b42ac --- /dev/null +++ b/src/test/ui/lint/lint-ctypes-73251-2.rs @@ -0,0 +1,32 @@ +#![feature(type_alias_impl_trait)] +#![deny(improper_ctypes)] + +pub trait TraitA { + type Assoc; +} + +impl TraitA for u32 { + type Assoc = u32; +} + +pub trait TraitB { + type Assoc; +} + +impl TraitB for T where T: TraitA { + type Assoc = ::Assoc; +} + +type AliasA = impl TraitA; + +type AliasB = impl TraitB; + +fn use_of_a() -> AliasA { 3 } + +fn use_of_b() -> AliasB { 3 } + +extern "C" { + pub fn lint_me() -> ::Assoc; //~ ERROR: uses type `impl TraitA` +} + +fn main() {} diff --git a/src/test/ui/lint/lint-ctypes-73251-2.stderr b/src/test/ui/lint/lint-ctypes-73251-2.stderr new file mode 100644 index 0000000000000..43f7629b043a9 --- /dev/null +++ b/src/test/ui/lint/lint-ctypes-73251-2.stderr @@ -0,0 +1,15 @@ +error: `extern` block uses type `impl TraitA`, which is not FFI-safe + --> $DIR/lint-ctypes-73251-2.rs:29:25 + | +LL | pub fn lint_me() -> ::Assoc; + | ^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe + | +note: the lint level is defined here + --> $DIR/lint-ctypes-73251-2.rs:2:9 + | +LL | #![deny(improper_ctypes)] + | ^^^^^^^^^^^^^^^ + = note: opaque types have no C equivalent + +error: aborting due to previous error + diff --git a/src/test/ui/lint/lint-ctypes-73251.rs b/src/test/ui/lint/lint-ctypes-73251.rs new file mode 100644 index 0000000000000..ebc2ca77b67a1 --- /dev/null +++ b/src/test/ui/lint/lint-ctypes-73251.rs @@ -0,0 +1,22 @@ +// check-pass + +#![feature(type_alias_impl_trait)] +#![deny(improper_ctypes)] + +pub trait Foo { + type Assoc; +} + +impl Foo for () { + type Assoc = u32; +} + +type Bar = impl Foo; + +fn assign() -> Bar {} + +extern "C" { + pub fn lint_me() -> ::Assoc; +} + +fn main() {} diff --git a/src/test/ui/specialization/deafult-associated-type-bound-1.rs b/src/test/ui/specialization/deafult-associated-type-bound-1.rs new file mode 100644 index 0000000000000..272a5e3fe10c6 --- /dev/null +++ b/src/test/ui/specialization/deafult-associated-type-bound-1.rs @@ -0,0 +1,24 @@ +// Check that we check that default associated types satisfy the required +// bounds on them. + +#![feature(specialization)] +//~^ WARNING `specialization` is incomplete + +trait X { + type U: Clone; + fn unsafe_clone(&self, x: Option<&Self::U>) { + x.cloned(); + } +} + +// We cannot normalize `::U` to `str` here, because the default could +// be overridden. The error here must therefore be found by a method other than +// normalization. +impl X for T { + default type U = str; + //~^ ERROR the trait bound `str: std::clone::Clone` is not satisfied +} + +pub fn main() { + 1.unsafe_clone(None); +} diff --git a/src/test/ui/specialization/deafult-associated-type-bound-1.stderr b/src/test/ui/specialization/deafult-associated-type-bound-1.stderr new file mode 100644 index 0000000000000..90ad5d4c1559b --- /dev/null +++ b/src/test/ui/specialization/deafult-associated-type-bound-1.stderr @@ -0,0 +1,21 @@ +warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/deafult-associated-type-bound-1.rs:4:12 + | +LL | #![feature(specialization)] + | ^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #31844 for more information + +error[E0277]: the trait bound `str: std::clone::Clone` is not satisfied + --> $DIR/deafult-associated-type-bound-1.rs:18:5 + | +LL | type U: Clone; + | -------------- required by `X::U` +... +LL | default type U = str; + | ^^^^^^^^^^^^^^^^^^^^^ the trait `std::clone::Clone` is not implemented for `str` + +error: aborting due to previous error; 1 warning emitted + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/specialization/deafult-associated-type-bound-2.rs b/src/test/ui/specialization/deafult-associated-type-bound-2.rs new file mode 100644 index 0000000000000..0a21b1f09106b --- /dev/null +++ b/src/test/ui/specialization/deafult-associated-type-bound-2.rs @@ -0,0 +1,22 @@ +// Check that generic predicates are also checked for default associated types. +#![feature(specialization)] +//~^ WARNING `specialization` is incomplete + +trait X { + type U: PartialEq; + fn unsafe_compare(x: Option, y: Option) { + match (x, y) { + (Some(a), Some(b)) => a == b, + _ => false, + }; + } +} + +impl X for T { + default type U = &'static B; + //~^ ERROR can't compare `&'static B` with `B` +} + +pub fn main() { + >::unsafe_compare(None, None); +} diff --git a/src/test/ui/specialization/deafult-associated-type-bound-2.stderr b/src/test/ui/specialization/deafult-associated-type-bound-2.stderr new file mode 100644 index 0000000000000..ea40f846e3665 --- /dev/null +++ b/src/test/ui/specialization/deafult-associated-type-bound-2.stderr @@ -0,0 +1,23 @@ +warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/deafult-associated-type-bound-2.rs:2:12 + | +LL | #![feature(specialization)] + | ^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #31844 for more information + +error[E0277]: can't compare `&'static B` with `B` + --> $DIR/deafult-associated-type-bound-2.rs:16:5 + | +LL | type U: PartialEq; + | --------------------- required by `X::U` +... +LL | default type U = &'static B; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ no implementation for `&'static B == B` + | + = help: the trait `std::cmp::PartialEq` is not implemented for `&'static B` + +error: aborting due to previous error; 1 warning emitted + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/specialization/deafult-generic-associated-type-bound.rs b/src/test/ui/specialization/deafult-generic-associated-type-bound.rs new file mode 100644 index 0000000000000..8a94ea658d2d0 --- /dev/null +++ b/src/test/ui/specialization/deafult-generic-associated-type-bound.rs @@ -0,0 +1,27 @@ +// Check that default generics associated types are validated. + +#![feature(specialization)] +#![feature(generic_associated_types)] +//~^^ WARNING `specialization` is incomplete +//~^^ WARNING the feature `generic_associated_types` is incomplete + +trait X { + type U<'a>: PartialEq<&'a Self>; + fn unsafe_compare<'b>(x: Option>, y: Option<&'b Self>) { + match (x, y) { + (Some(a), Some(b)) => a == b, + _ => false, + }; + } +} + +impl X for T { + default type U<'a> = &'a T; + //~^ ERROR can't compare `T` with `T` +} + +struct NotComparable; + +pub fn main() { + ::unsafe_compare(None, None); +} diff --git a/src/test/ui/specialization/deafult-generic-associated-type-bound.stderr b/src/test/ui/specialization/deafult-generic-associated-type-bound.stderr new file mode 100644 index 0000000000000..7f3c49e753fd7 --- /dev/null +++ b/src/test/ui/specialization/deafult-generic-associated-type-bound.stderr @@ -0,0 +1,36 @@ +warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/deafult-generic-associated-type-bound.rs:3:12 + | +LL | #![feature(specialization)] + | ^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #31844 for more information + +warning: the feature `generic_associated_types` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/deafult-generic-associated-type-bound.rs:4:12 + | +LL | #![feature(generic_associated_types)] + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #44265 for more information + +error[E0277]: can't compare `T` with `T` + --> $DIR/deafult-generic-associated-type-bound.rs:19:5 + | +LL | type U<'a>: PartialEq<&'a Self>; + | -------------------------------- required by `X::U` +... +LL | default type U<'a> = &'a T; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ no implementation for `T == T` + | + = help: the trait `std::cmp::PartialEq` is not implemented for `T` + = note: required because of the requirements on the impl of `std::cmp::PartialEq` for `&'a T` +help: consider further restricting this bound + | +LL | impl X for T { + | ^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error; 2 warnings emitted + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/traits/trait-suggest-deferences-issue-39029.fixed b/src/test/ui/traits/trait-suggest-deferences-issue-39029.fixed new file mode 100644 index 0000000000000..2bb34b0ebee6f --- /dev/null +++ b/src/test/ui/traits/trait-suggest-deferences-issue-39029.fixed @@ -0,0 +1,18 @@ +// run-rustfix +use std::net::TcpListener; + +struct NoToSocketAddrs(String); + +impl std::ops::Deref for NoToSocketAddrs { + type Target = String; + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +fn main() { + let _works = TcpListener::bind("some string"); + let bad = NoToSocketAddrs("bad".to_owned()); + let _errors = TcpListener::bind(&*bad); + //~^ ERROR the trait bound `NoToSocketAddrs: std::net::ToSocketAddrs` is not satisfied +} diff --git a/src/test/ui/traits/trait-suggest-deferences-issue-39029.rs b/src/test/ui/traits/trait-suggest-deferences-issue-39029.rs new file mode 100644 index 0000000000000..33d524608a058 --- /dev/null +++ b/src/test/ui/traits/trait-suggest-deferences-issue-39029.rs @@ -0,0 +1,18 @@ +// run-rustfix +use std::net::TcpListener; + +struct NoToSocketAddrs(String); + +impl std::ops::Deref for NoToSocketAddrs { + type Target = String; + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +fn main() { + let _works = TcpListener::bind("some string"); + let bad = NoToSocketAddrs("bad".to_owned()); + let _errors = TcpListener::bind(&bad); + //~^ ERROR the trait bound `NoToSocketAddrs: std::net::ToSocketAddrs` is not satisfied +} diff --git a/src/test/ui/traits/trait-suggest-deferences-issue-39029.stderr b/src/test/ui/traits/trait-suggest-deferences-issue-39029.stderr new file mode 100644 index 0000000000000..0bf9794a744c9 --- /dev/null +++ b/src/test/ui/traits/trait-suggest-deferences-issue-39029.stderr @@ -0,0 +1,19 @@ +error[E0277]: the trait bound `NoToSocketAddrs: std::net::ToSocketAddrs` is not satisfied + --> $DIR/trait-suggest-deferences-issue-39029.rs:16:37 + | +LL | let _errors = TcpListener::bind(&bad); + | ^^^^ + | | + | the trait `std::net::ToSocketAddrs` is not implemented for `NoToSocketAddrs` + | help: consider adding dereference here: `&*bad` + | + ::: $SRC_DIR/libstd/net/tcp.rs:LL:COL + | +LL | pub fn bind(addr: A) -> io::Result { + | ------------- required by this bound in `std::net::TcpListener::bind` + | + = note: required because of the requirements on the impl of `std::net::ToSocketAddrs` for `&NoToSocketAddrs` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/traits/trait-suggest-deferences-issue-62530.fixed b/src/test/ui/traits/trait-suggest-deferences-issue-62530.fixed new file mode 100644 index 0000000000000..fa7b9167d8d7f --- /dev/null +++ b/src/test/ui/traits/trait-suggest-deferences-issue-62530.fixed @@ -0,0 +1,15 @@ +// run-rustfix +fn takes_str(_x: &str) {} + +fn takes_type_parameter(_x: T) where T: SomeTrait {} + +trait SomeTrait {} +impl SomeTrait for &'_ str {} +impl SomeTrait for char {} + +fn main() { + let string = String::new(); + takes_str(&string); // Ok + takes_type_parameter(&*string); // Error + //~^ ERROR the trait bound `&std::string::String: SomeTrait` is not satisfied +} diff --git a/src/test/ui/traits/trait-suggest-deferences-issue-62530.rs b/src/test/ui/traits/trait-suggest-deferences-issue-62530.rs new file mode 100644 index 0000000000000..e785f01217735 --- /dev/null +++ b/src/test/ui/traits/trait-suggest-deferences-issue-62530.rs @@ -0,0 +1,15 @@ +// run-rustfix +fn takes_str(_x: &str) {} + +fn takes_type_parameter(_x: T) where T: SomeTrait {} + +trait SomeTrait {} +impl SomeTrait for &'_ str {} +impl SomeTrait for char {} + +fn main() { + let string = String::new(); + takes_str(&string); // Ok + takes_type_parameter(&string); // Error + //~^ ERROR the trait bound `&std::string::String: SomeTrait` is not satisfied +} diff --git a/src/test/ui/traits/trait-suggest-deferences-issue-62530.stderr b/src/test/ui/traits/trait-suggest-deferences-issue-62530.stderr new file mode 100644 index 0000000000000..9c2a582638ecb --- /dev/null +++ b/src/test/ui/traits/trait-suggest-deferences-issue-62530.stderr @@ -0,0 +1,15 @@ +error[E0277]: the trait bound `&std::string::String: SomeTrait` is not satisfied + --> $DIR/trait-suggest-deferences-issue-62530.rs:13:26 + | +LL | fn takes_type_parameter(_x: T) where T: SomeTrait {} + | --------- required by this bound in `takes_type_parameter` +... +LL | takes_type_parameter(&string); // Error + | ^^^^^^^ + | | + | the trait `SomeTrait` is not implemented for `&std::string::String` + | help: consider adding dereference here: `&*string` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/traits/trait-suggest-deferences-multiple-0.fixed b/src/test/ui/traits/trait-suggest-deferences-multiple-0.fixed new file mode 100644 index 0000000000000..b7160b75c605e --- /dev/null +++ b/src/test/ui/traits/trait-suggest-deferences-multiple-0.fixed @@ -0,0 +1,36 @@ +// run-rustfix +use std::ops::Deref; + +trait Happy {} +struct LDM; +impl Happy for &LDM {} + +struct Foo(LDM); +struct Bar(Foo); +struct Baz(Bar); +impl Deref for Foo { + type Target = LDM; + fn deref(&self) -> &Self::Target { + &self.0 + } +} +impl Deref for Bar { + type Target = Foo; + fn deref(&self) -> &Self::Target { + &self.0 + } +} +impl Deref for Baz { + type Target = Bar; + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +fn foo(_: T) where T: Happy {} + +fn main() { + let baz = Baz(Bar(Foo(LDM))); + foo(&***baz); + //~^ ERROR the trait bound `&Baz: Happy` is not satisfied +} diff --git a/src/test/ui/traits/trait-suggest-deferences-multiple-0.rs b/src/test/ui/traits/trait-suggest-deferences-multiple-0.rs new file mode 100644 index 0000000000000..9ac55177ffadd --- /dev/null +++ b/src/test/ui/traits/trait-suggest-deferences-multiple-0.rs @@ -0,0 +1,36 @@ +// run-rustfix +use std::ops::Deref; + +trait Happy {} +struct LDM; +impl Happy for &LDM {} + +struct Foo(LDM); +struct Bar(Foo); +struct Baz(Bar); +impl Deref for Foo { + type Target = LDM; + fn deref(&self) -> &Self::Target { + &self.0 + } +} +impl Deref for Bar { + type Target = Foo; + fn deref(&self) -> &Self::Target { + &self.0 + } +} +impl Deref for Baz { + type Target = Bar; + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +fn foo(_: T) where T: Happy {} + +fn main() { + let baz = Baz(Bar(Foo(LDM))); + foo(&baz); + //~^ ERROR the trait bound `&Baz: Happy` is not satisfied +} diff --git a/src/test/ui/traits/trait-suggest-deferences-multiple-0.stderr b/src/test/ui/traits/trait-suggest-deferences-multiple-0.stderr new file mode 100644 index 0000000000000..add34a553bc9f --- /dev/null +++ b/src/test/ui/traits/trait-suggest-deferences-multiple-0.stderr @@ -0,0 +1,15 @@ +error[E0277]: the trait bound `&Baz: Happy` is not satisfied + --> $DIR/trait-suggest-deferences-multiple-0.rs:34:9 + | +LL | fn foo(_: T) where T: Happy {} + | ----- required by this bound in `foo` +... +LL | foo(&baz); + | ^^^^ + | | + | the trait `Happy` is not implemented for `&Baz` + | help: consider adding dereference here: `&***baz` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/traits/trait-suggest-deferences-multiple-1.rs b/src/test/ui/traits/trait-suggest-deferences-multiple-1.rs new file mode 100644 index 0000000000000..91c6c7924a408 --- /dev/null +++ b/src/test/ui/traits/trait-suggest-deferences-multiple-1.rs @@ -0,0 +1,54 @@ +use std::ops::{Deref, DerefMut}; + +trait Happy {} +struct LDM; +impl Happy for &mut LDM {} + +struct Foo(LDM); +struct Bar(Foo); +struct Baz(Bar); +impl Deref for Foo { + type Target = LDM; + fn deref(&self) -> &Self::Target { + &self.0 + } +} +impl Deref for Bar { + type Target = Foo; + fn deref(&self) -> &Self::Target { + &self.0 + } +} +impl Deref for Baz { + type Target = Bar; + fn deref(&self) -> &Self::Target { + &self.0 + } +} +impl DerefMut for Foo { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} +impl DerefMut for Bar { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} +impl DerefMut for Baz { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} + + +fn foo(_: T) where T: Happy {} + +fn main() { + // Currently the compiler doesn't try to suggest dereferences for situations + // where DerefMut involves. So this test is meant to ensure compiler doesn't + // generate incorrect help message. + let mut baz = Baz(Bar(Foo(LDM))); + foo(&mut baz); + //~^ ERROR the trait bound `&mut Baz: Happy` is not satisfied +} diff --git a/src/test/ui/traits/trait-suggest-deferences-multiple-1.stderr b/src/test/ui/traits/trait-suggest-deferences-multiple-1.stderr new file mode 100644 index 0000000000000..e90278fa16f0e --- /dev/null +++ b/src/test/ui/traits/trait-suggest-deferences-multiple-1.stderr @@ -0,0 +1,12 @@ +error[E0277]: the trait bound `&mut Baz: Happy` is not satisfied + --> $DIR/trait-suggest-deferences-multiple-1.rs:52:9 + | +LL | fn foo(_: T) where T: Happy {} + | ----- required by this bound in `foo` +... +LL | foo(&mut baz); + | ^^^^^^^^ the trait `Happy` is not implemented for `&mut Baz` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/where-clauses/where-lifetime-resolution.rs b/src/test/ui/where-clauses/where-lifetime-resolution.rs index 0d426386768c8..d8677ee959abd 100644 --- a/src/test/ui/where-clauses/where-lifetime-resolution.rs +++ b/src/test/ui/where-clauses/where-lifetime-resolution.rs @@ -7,7 +7,6 @@ fn f() where //~^ ERROR use of undeclared lifetime name `'a` for<'a> dyn for<'b> Trait2<'a, 'b>: Trait2<'a, 'b>, //~^ ERROR use of undeclared lifetime name `'b` - //~| ERROR nested quantification of lifetimes {} fn main() {} diff --git a/src/test/ui/where-clauses/where-lifetime-resolution.stderr b/src/test/ui/where-clauses/where-lifetime-resolution.stderr index 49799a93017eb..6c52664154bbf 100644 --- a/src/test/ui/where-clauses/where-lifetime-resolution.stderr +++ b/src/test/ui/where-clauses/where-lifetime-resolution.stderr @@ -7,12 +7,6 @@ LL | for<'a> dyn Trait1<'a>: Trait1<'a>, // OK LL | (dyn for<'a> Trait1<'a>): Trait1<'a>, | ^^ undeclared lifetime -error[E0316]: nested quantification of lifetimes - --> $DIR/where-lifetime-resolution.rs:8:17 - | -LL | for<'a> dyn for<'b> Trait2<'a, 'b>: Trait2<'a, 'b>, - | ^^^^^^^^^^^^^^^^^^^^^^ - error[E0261]: use of undeclared lifetime name `'b` --> $DIR/where-lifetime-resolution.rs:8:52 | @@ -22,6 +16,6 @@ LL | fn f() where LL | for<'a> dyn for<'b> Trait2<'a, 'b>: Trait2<'a, 'b>, | ^^ undeclared lifetime -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0261`.