From b345e18462b235ad74dc01166702c0d8e9587a97 Mon Sep 17 00:00:00 2001 From: Noah Lev Date: Fri, 3 Dec 2021 19:43:50 -0800 Subject: [PATCH 01/10] rustdoc: Coalesce some `run_test` args as one `LangString` arg --- src/librustdoc/doctest.rs | 32 +++++++++++++------------------- 1 file changed, 13 insertions(+), 19 deletions(-) diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs index 56ccdfae1d8bc..67b764cdfd5bf 100644 --- a/src/librustdoc/doctest.rs +++ b/src/librustdoc/doctest.rs @@ -293,14 +293,11 @@ fn run_test( crate_name: &str, line: usize, options: Options, - should_panic: bool, + mut lang_string: LangString, no_run: bool, - as_test_harness: bool, runtool: Option, runtool_args: Vec, target: TargetTriple, - compile_fail: bool, - mut error_codes: Vec, opts: &TestOptions, edition: Edition, outdir: DirState, @@ -309,7 +306,7 @@ fn run_test( report_unused_externs: impl Fn(UnusedExterns), ) -> Result<(), TestFailure> { let (test, line_offset, supports_color) = - make_test(test, Some(crate_name), as_test_harness, opts, edition, Some(test_id)); + make_test(test, Some(crate_name), lang_string.test_harness, opts, edition, Some(test_id)); let output_file = outdir.path().join("rust_out"); @@ -329,10 +326,10 @@ fn run_test( compiler.env("UNSTABLE_RUSTDOC_TEST_PATH", path); compiler.env("UNSTABLE_RUSTDOC_TEST_LINE", format!("{}", line as isize - line_offset as isize)); compiler.arg("-o").arg(&output_file); - if as_test_harness { + if lang_string.test_harness { compiler.arg("--test"); } - if options.json_unused_externs && !compile_fail { + if options.json_unused_externs && !lang_string.compile_fail { compiler.arg("--error-format=json"); compiler.arg("--json").arg("unused-externs"); compiler.arg("-Z").arg("unstable-options"); @@ -351,7 +348,7 @@ fn run_test( for debugging_option_str in &options.debugging_opts_strs { compiler.arg("-Z").arg(&debugging_option_str); } - if no_run && !compile_fail && options.persist_doctests.is_none() { + if no_run && !lang_string.compile_fail && options.persist_doctests.is_none() { compiler.arg("--emit=metadata"); } compiler.arg("--target").arg(match target { @@ -418,20 +415,20 @@ fn run_test( let out = out_lines.join("\n"); let _bomb = Bomb(&out); - match (output.status.success(), compile_fail) { + match (output.status.success(), lang_string.compile_fail) { (true, true) => { return Err(TestFailure::UnexpectedCompilePass); } (true, false) => {} (false, true) => { - if !error_codes.is_empty() { + if !lang_string.error_codes.is_empty() { // We used to check if the output contained "error[{}]: " but since we added the // colored output, we can't anymore because of the color escape characters before // the ":". - error_codes.retain(|err| !out.contains(&format!("error[{}]", err))); + lang_string.error_codes.retain(|err| !out.contains(&format!("error[{}]", err))); - if !error_codes.is_empty() { - return Err(TestFailure::MissingErrorCodes(error_codes)); + if !lang_string.error_codes.is_empty() { + return Err(TestFailure::MissingErrorCodes(lang_string.error_codes)); } } } @@ -470,9 +467,9 @@ fn run_test( match result { Err(e) => return Err(TestFailure::ExecutionError(e)), Ok(out) => { - if should_panic && out.status.success() { + if lang_string.should_panic && out.status.success() { return Err(TestFailure::UnexpectedRunPass); - } else if !should_panic && !out.status.success() { + } else if !lang_string.should_panic && !out.status.success() { return Err(TestFailure::ExecutionFailure(out)); } } @@ -966,14 +963,11 @@ impl Tester for Collector { &crate_name, line, options, - config.should_panic, + config, no_run, - config.test_harness, runtool, runtool_args, target, - config.compile_fail, - config.error_codes, &opts, edition, outdir, From 5e33e6affd0d3d207d4a0d65a9a91de2f0792a23 Mon Sep 17 00:00:00 2001 From: Noah Lev Date: Fri, 3 Dec 2021 19:49:31 -0800 Subject: [PATCH 02/10] Rename `TestOptions` to `GlobalTestOptions` It seems to apply to all doctests in the crate. --- src/librustdoc/doctest.rs | 15 ++++++++------- src/librustdoc/doctest/tests.rs | 34 ++++++++++++++++----------------- src/librustdoc/markdown.rs | 4 ++-- 3 files changed, 27 insertions(+), 26 deletions(-) diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs index 67b764cdfd5bf..96ed9a15454d1 100644 --- a/src/librustdoc/doctest.rs +++ b/src/librustdoc/doctest.rs @@ -34,8 +34,9 @@ use crate::html::markdown::{self, ErrorCodes, Ignore, LangString}; use crate::lint::init_lints; use crate::passes::span_of_attrs; +/// Options that apply to all doctests in a crate or Markdown file (for `rustdoc foo.md`). #[derive(Clone, Default)] -crate struct TestOptions { +crate struct GlobalTestOptions { /// Whether to disable the default `extern crate my_crate;` when creating doctests. crate no_crate_inject: bool, /// Additional crate-level attributes to add to doctests. @@ -214,10 +215,10 @@ crate fn run_tests(mut test_args: Vec, nocapture: bool, tests: Vec TestOptions { +fn scrape_test_config(attrs: &[ast::Attribute]) -> GlobalTestOptions { use rustc_ast_pretty::pprust; - let mut opts = TestOptions { no_crate_inject: false, attrs: Vec::new() }; + let mut opts = GlobalTestOptions { no_crate_inject: false, attrs: Vec::new() }; let test_attrs: Vec<_> = attrs .iter() @@ -298,7 +299,7 @@ fn run_test( runtool: Option, runtool_args: Vec, target: TargetTriple, - opts: &TestOptions, + opts: &GlobalTestOptions, edition: Edition, outdir: DirState, path: PathBuf, @@ -484,7 +485,7 @@ crate fn make_test( s: &str, crate_name: Option<&str>, dont_insert_main: bool, - opts: &TestOptions, + opts: &GlobalTestOptions, edition: Edition, test_id: Option<&str>, ) -> (String, usize, bool) { @@ -805,7 +806,7 @@ crate struct Collector { use_headers: bool, enable_per_target_ignores: bool, crate_name: Symbol, - opts: TestOptions, + opts: GlobalTestOptions, position: Span, source_map: Option>, filename: Option, @@ -819,7 +820,7 @@ impl Collector { crate_name: Symbol, options: Options, use_headers: bool, - opts: TestOptions, + opts: GlobalTestOptions, source_map: Option>, filename: Option, enable_per_target_ignores: bool, diff --git a/src/librustdoc/doctest/tests.rs b/src/librustdoc/doctest/tests.rs index 099609d0f912e..360d2259ea3d2 100644 --- a/src/librustdoc/doctest/tests.rs +++ b/src/librustdoc/doctest/tests.rs @@ -1,10 +1,10 @@ -use super::{make_test, TestOptions}; +use super::{make_test, GlobalTestOptions}; use rustc_span::edition::DEFAULT_EDITION; #[test] fn make_test_basic() { //basic use: wraps with `fn main`, adds `#![allow(unused)]` - let opts = TestOptions::default(); + let opts = GlobalTestOptions::default(); let input = "assert_eq!(2+2, 4);"; let expected = "#![allow(unused)] fn main() { @@ -19,7 +19,7 @@ assert_eq!(2+2, 4); fn make_test_crate_name_no_use() { // If you give a crate name but *don't* use it within the test, it won't bother inserting // the `extern crate` statement. - let opts = TestOptions::default(); + let opts = GlobalTestOptions::default(); let input = "assert_eq!(2+2, 4);"; let expected = "#![allow(unused)] fn main() { @@ -34,7 +34,7 @@ assert_eq!(2+2, 4); fn make_test_crate_name() { // If you give a crate name and use it within the test, it will insert an `extern crate` // statement before `fn main`. - let opts = TestOptions::default(); + let opts = GlobalTestOptions::default(); let input = "use asdf::qwop; assert_eq!(2+2, 4);"; let expected = "#![allow(unused)] @@ -52,7 +52,7 @@ assert_eq!(2+2, 4); fn make_test_no_crate_inject() { // Even if you do use the crate within the test, setting `opts.no_crate_inject` will skip // adding it anyway. - let opts = TestOptions { no_crate_inject: true, attrs: vec![] }; + let opts = GlobalTestOptions { no_crate_inject: true, attrs: vec![] }; let input = "use asdf::qwop; assert_eq!(2+2, 4);"; let expected = "#![allow(unused)] @@ -70,7 +70,7 @@ fn make_test_ignore_std() { // Even if you include a crate name, and use it in the doctest, we still won't include an // `extern crate` statement if the crate is "std" -- that's included already by the // compiler! - let opts = TestOptions::default(); + let opts = GlobalTestOptions::default(); let input = "use std::*; assert_eq!(2+2, 4);"; let expected = "#![allow(unused)] @@ -87,7 +87,7 @@ assert_eq!(2+2, 4); fn make_test_manual_extern_crate() { // When you manually include an `extern crate` statement in your doctest, `make_test` // assumes you've included one for your own crate too. - let opts = TestOptions::default(); + let opts = GlobalTestOptions::default(); let input = "extern crate asdf; use asdf::qwop; assert_eq!(2+2, 4);"; @@ -104,7 +104,7 @@ assert_eq!(2+2, 4); #[test] fn make_test_manual_extern_crate_with_macro_use() { - let opts = TestOptions::default(); + let opts = GlobalTestOptions::default(); let input = "#[macro_use] extern crate asdf; use asdf::qwop; assert_eq!(2+2, 4);"; @@ -123,7 +123,7 @@ assert_eq!(2+2, 4); fn make_test_opts_attrs() { // If you supplied some doctest attributes with `#![doc(test(attr(...)))]`, it will use // those instead of the stock `#![allow(unused)]`. - let mut opts = TestOptions::default(); + let mut opts = GlobalTestOptions::default(); opts.attrs.push("feature(sick_rad)".to_string()); let input = "use asdf::qwop; assert_eq!(2+2, 4);"; @@ -155,7 +155,7 @@ assert_eq!(2+2, 4); fn make_test_crate_attrs() { // Including inner attributes in your doctest will apply them to the whole "crate", pasting // them outside the generated main function. - let opts = TestOptions::default(); + let opts = GlobalTestOptions::default(); let input = "#![feature(sick_rad)] assert_eq!(2+2, 4);"; let expected = "#![allow(unused)] @@ -171,7 +171,7 @@ assert_eq!(2+2, 4); #[test] fn make_test_with_main() { // Including your own `fn main` wrapper lets the test use it verbatim. - let opts = TestOptions::default(); + let opts = GlobalTestOptions::default(); let input = "fn main() { assert_eq!(2+2, 4); }"; @@ -187,7 +187,7 @@ fn main() { #[test] fn make_test_fake_main() { // ... but putting it in a comment will still provide a wrapper. - let opts = TestOptions::default(); + let opts = GlobalTestOptions::default(); let input = "//Ceci n'est pas une `fn main` assert_eq!(2+2, 4);"; let expected = "#![allow(unused)] @@ -203,7 +203,7 @@ assert_eq!(2+2, 4); #[test] fn make_test_dont_insert_main() { // Even with that, if you set `dont_insert_main`, it won't create the `fn main` wrapper. - let opts = TestOptions::default(); + let opts = GlobalTestOptions::default(); let input = "//Ceci n'est pas une `fn main` assert_eq!(2+2, 4);"; let expected = "#![allow(unused)] @@ -216,7 +216,7 @@ assert_eq!(2+2, 4);" #[test] fn make_test_issues_21299_33731() { - let opts = TestOptions::default(); + let opts = GlobalTestOptions::default(); let input = "// fn main assert_eq!(2+2, 4);"; @@ -248,7 +248,7 @@ assert_eq!(asdf::foo, 4); #[test] fn make_test_main_in_macro() { - let opts = TestOptions::default(); + let opts = GlobalTestOptions::default(); let input = "#[macro_use] extern crate my_crate; test_wrapper! { fn main() {} @@ -267,7 +267,7 @@ test_wrapper! { #[test] fn make_test_returns_result() { // creates an inner function and unwraps it - let opts = TestOptions::default(); + let opts = GlobalTestOptions::default(); let input = "use std::io; let mut input = String::new(); io::stdin().read_line(&mut input)?; @@ -287,7 +287,7 @@ Ok::<(), io:Error>(()) #[test] fn make_test_named_wrapper() { // creates an inner function with a specific name - let opts = TestOptions::default(); + let opts = GlobalTestOptions::default(); let input = "assert_eq!(2+2, 4);"; let expected = "#![allow(unused)] fn main() { #[allow(non_snake_case)] fn _doctest_main__some_unique_name() { diff --git a/src/librustdoc/markdown.rs b/src/librustdoc/markdown.rs index abb4bec5ca133..906b8f8a24570 100644 --- a/src/librustdoc/markdown.rs +++ b/src/librustdoc/markdown.rs @@ -7,7 +7,7 @@ use rustc_span::source_map::DUMMY_SP; use rustc_span::Symbol; use crate::config::{Options, RenderOptions}; -use crate::doctest::{Collector, TestOptions}; +use crate::doctest::{Collector, GlobalTestOptions}; use crate::html::escape::Escape; use crate::html::markdown; use crate::html::markdown::{ @@ -129,7 +129,7 @@ crate fn render>( crate fn test(options: Options) -> Result<(), String> { let input_str = read_to_string(&options.input) .map_err(|err| format!("{}: {}", options.input.display(), err))?; - let mut opts = TestOptions::default(); + let mut opts = GlobalTestOptions::default(); opts.no_crate_inject = true; let mut collector = Collector::new( Symbol::intern(&options.input.display().to_string()), From 9afa190c446d4fc9c4b73eae11f67af46584cf98 Mon Sep 17 00:00:00 2001 From: Noah Lev Date: Fri, 3 Dec 2021 19:54:38 -0800 Subject: [PATCH 03/10] doctest: Rename `options` to `rustdoc_options` These are the rustdoc-wide options. It's easy to confuse them with options for doctests in particular, so this change should help. --- src/librustdoc/doctest.rs | 52 +++++++++++++++++++-------------------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs index 96ed9a15454d1..ac24543929b66 100644 --- a/src/librustdoc/doctest.rs +++ b/src/librustdoc/doctest.rs @@ -29,7 +29,7 @@ use std::sync::atomic::{AtomicUsize, Ordering}; use std::sync::{Arc, Mutex}; use crate::clean::{types::AttributesExt, Attributes}; -use crate::config::Options; +use crate::config::Options as RustdocOptions; use crate::html::markdown::{self, ErrorCodes, Ignore, LangString}; use crate::lint::init_lints; use crate::passes::span_of_attrs; @@ -43,7 +43,7 @@ crate struct GlobalTestOptions { crate attrs: Vec, } -crate fn run(options: Options) -> Result<(), ErrorReported> { +crate fn run(options: RustdocOptions) -> Result<(), ErrorReported> { let input = config::Input::File(options.input.clone()); let invalid_codeblock_attributes_name = crate::lint::INVALID_CODEBLOCK_ATTRIBUTES.name; @@ -293,7 +293,7 @@ fn run_test( test: &str, crate_name: &str, line: usize, - options: Options, + rustdoc_options: RustdocOptions, mut lang_string: LangString, no_run: bool, runtool: Option, @@ -311,16 +311,16 @@ fn run_test( let output_file = outdir.path().join("rust_out"); - let rustc_binary = options + let rustc_binary = rustdoc_options .test_builder .as_deref() .unwrap_or_else(|| rustc_interface::util::rustc_path().expect("found rustc")); let mut compiler = Command::new(&rustc_binary); compiler.arg("--crate-type").arg("bin"); - for cfg in &options.cfgs { + for cfg in &rustdoc_options.cfgs { compiler.arg("--cfg").arg(&cfg); } - if let Some(sysroot) = options.maybe_sysroot { + if let Some(sysroot) = rustdoc_options.maybe_sysroot { compiler.arg("--sysroot").arg(sysroot); } compiler.arg("--edition").arg(&edition.to_string()); @@ -330,26 +330,26 @@ fn run_test( if lang_string.test_harness { compiler.arg("--test"); } - if options.json_unused_externs && !lang_string.compile_fail { + if rustdoc_options.json_unused_externs && !lang_string.compile_fail { compiler.arg("--error-format=json"); compiler.arg("--json").arg("unused-externs"); compiler.arg("-Z").arg("unstable-options"); compiler.arg("-W").arg("unused_crate_dependencies"); } - for lib_str in &options.lib_strs { + for lib_str in &rustdoc_options.lib_strs { compiler.arg("-L").arg(&lib_str); } - for extern_str in &options.extern_strs { + for extern_str in &rustdoc_options.extern_strs { compiler.arg("--extern").arg(&extern_str); } compiler.arg("-Ccodegen-units=1"); - for codegen_options_str in &options.codegen_options_strs { + for codegen_options_str in &rustdoc_options.codegen_options_strs { compiler.arg("-C").arg(&codegen_options_str); } - for debugging_option_str in &options.debugging_opts_strs { + for debugging_option_str in &rustdoc_options.debugging_opts_strs { compiler.arg("-Z").arg(&debugging_option_str); } - if no_run && !lang_string.compile_fail && options.persist_doctests.is_none() { + if no_run && !lang_string.compile_fail && rustdoc_options.persist_doctests.is_none() { compiler.arg("--emit=metadata"); } compiler.arg("--target").arg(match target { @@ -358,7 +358,7 @@ fn run_test( path.to_str().expect("target path must be valid unicode").to_string() } }); - if let ErrorOutputType::HumanReadable(kind) = options.error_format { + if let ErrorOutputType::HumanReadable(kind) = rustdoc_options.error_format { let (short, color_config) = kind.unzip(); if short { @@ -452,11 +452,11 @@ fn run_test( } else { cmd = Command::new(output_file); } - if let Some(run_directory) = options.test_run_directory { + if let Some(run_directory) = rustdoc_options.test_run_directory { cmd.current_dir(run_directory); } - let result = if options.nocapture { + let result = if rustdoc_options.nocapture { cmd.status().map(|status| process::Output { status, stdout: Vec::new(), @@ -802,7 +802,7 @@ crate struct Collector { // the `names` vector of that test will be `["Title", "Subtitle"]`. names: Vec, - options: Options, + rustdoc_options: RustdocOptions, use_headers: bool, enable_per_target_ignores: bool, crate_name: Symbol, @@ -818,7 +818,7 @@ crate struct Collector { impl Collector { crate fn new( crate_name: Symbol, - options: Options, + rustdoc_options: RustdocOptions, use_headers: bool, opts: GlobalTestOptions, source_map: Option>, @@ -828,7 +828,7 @@ impl Collector { Collector { tests: Vec::new(), names: Vec::new(), - options, + rustdoc_options, use_headers, enable_per_target_ignores, crate_name, @@ -882,14 +882,14 @@ impl Tester for Collector { let name = self.generate_name(line, &filename); let crate_name = self.crate_name.to_string(); let opts = self.opts.clone(); - let edition = config.edition.unwrap_or(self.options.edition); - let options = self.options.clone(); - let runtool = self.options.runtool.clone(); - let runtool_args = self.options.runtool_args.clone(); - let target = self.options.target.clone(); + let edition = config.edition.unwrap_or(self.rustdoc_options.edition); + let rustdoc_options = self.rustdoc_options.clone(); + let runtool = self.rustdoc_options.runtool.clone(); + let runtool_args = self.rustdoc_options.runtool_args.clone(); + let target = self.rustdoc_options.target.clone(); let target_str = target.to_string(); let unused_externs = self.unused_extern_reports.clone(); - let no_run = config.no_run || options.no_run; + let no_run = config.no_run || rustdoc_options.no_run; if !config.compile_fail { self.compiling_test_count.fetch_add(1, Ordering::SeqCst); } @@ -923,7 +923,7 @@ impl Tester for Collector { self.visited_tests.entry((file.clone(), line)).and_modify(|v| *v += 1).or_insert(0) }, ); - let outdir = if let Some(mut path) = options.persist_doctests.clone() { + let outdir = if let Some(mut path) = rustdoc_options.persist_doctests.clone() { path.push(&test_id); std::fs::create_dir_all(&path) @@ -963,7 +963,7 @@ impl Tester for Collector { &test, &crate_name, line, - options, + rustdoc_options, config, no_run, runtool, From 5ab1329b58dd9150c994fb6ebda128759c5ab3e5 Mon Sep 17 00:00:00 2001 From: Ellen Date: Mon, 13 Dec 2021 03:16:00 +0000 Subject: [PATCH 04/10] hurray for portable simd finding a nice test for this FIXME --- compiler/rustc_typeck/src/astconv/mod.rs | 88 +++++++------------ .../generic_arg_infer/issue-91614.rs | 8 ++ .../generic_arg_infer/issue-91614.stderr | 18 ++++ 3 files changed, 59 insertions(+), 55 deletions(-) create mode 100644 src/test/ui/const-generics/generic_arg_infer/issue-91614.rs create mode 100644 src/test/ui/const-generics/generic_arg_infer/issue-91614.stderr diff --git a/compiler/rustc_typeck/src/astconv/mod.rs b/compiler/rustc_typeck/src/astconv/mod.rs index dc52c49499a58..a45a7c745cc04 100644 --- a/compiler/rustc_typeck/src/astconv/mod.rs +++ b/compiler/rustc_typeck/src/astconv/mod.rs @@ -414,34 +414,40 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { arg: &GenericArg<'_>, ) -> subst::GenericArg<'tcx> { let tcx = self.astconv.tcx(); + + let mut handle_ty_args = |has_default, ty: &hir::Ty<'_>| { + if has_default { + tcx.check_optional_stability( + param.def_id, + Some(arg.id()), + arg.span(), + None, + |_, _| { + // Default generic parameters may not be marked + // with stability attributes, i.e. when the + // default parameter was defined at the same time + // as the rest of the type. As such, we ignore missing + // stability attributes. + }, + ) + } + if let (hir::TyKind::Infer, false) = (&ty.kind, self.astconv.allow_ty_infer()) { + self.inferred_params.push(ty.span); + tcx.ty_error().into() + } else { + self.astconv.ast_ty_to_ty(ty).into() + } + }; + match (¶m.kind, arg) { (GenericParamDefKind::Lifetime, GenericArg::Lifetime(lt)) => { self.astconv.ast_region_to_region(lt, Some(param)).into() } (&GenericParamDefKind::Type { has_default, .. }, GenericArg::Type(ty)) => { - if has_default { - tcx.check_optional_stability( - param.def_id, - Some(arg.id()), - arg.span(), - None, - |_, _| { - // Default generic parameters may not be marked - // with stability attributes, i.e. when the - // default parameter was defined at the same time - // as the rest of the type. As such, we ignore missing - // stability attributes. - }, - ) - } - if let (hir::TyKind::Infer, false) = - (&ty.kind, self.astconv.allow_ty_infer()) - { - self.inferred_params.push(ty.span); - tcx.ty_error().into() - } else { - self.astconv.ast_ty_to_ty(ty).into() - } + handle_ty_args(has_default, ty) + } + (&GenericParamDefKind::Type { has_default, .. }, GenericArg::Infer(inf)) => { + handle_ty_args(has_default, &inf.to_ty()) } (GenericParamDefKind::Const { .. }, GenericArg::Const(ct)) => { ty::Const::from_opt_const_arg_anon_const( @@ -453,41 +459,13 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { ) .into() } - (&GenericParamDefKind::Const { has_default }, hir::GenericArg::Infer(inf)) => { - if has_default { - tcx.const_param_default(param.def_id).into() - } else if self.astconv.allow_ty_infer() { - // FIXME(const_generics): Actually infer parameter here? - todo!() - } else { - self.inferred_params.push(inf.span); - tcx.ty_error().into() - } - } - ( - &GenericParamDefKind::Type { has_default, .. }, - hir::GenericArg::Infer(inf), - ) => { - if has_default { - tcx.check_optional_stability( - param.def_id, - Some(arg.id()), - arg.span(), - None, - |_, _| { - // Default generic parameters may not be marked - // with stability attributes, i.e. when the - // default parameter was defined at the same time - // as the rest of the type. As such, we ignore missing - // stability attributes. - }, - ); - } + (&GenericParamDefKind::Const { .. }, hir::GenericArg::Infer(inf)) => { + let ty = tcx.at(self.span).type_of(param.def_id); if self.astconv.allow_ty_infer() { - self.astconv.ast_ty_to_ty(&inf.to_ty()).into() + self.astconv.ct_infer(ty, Some(param), inf.span).into() } else { self.inferred_params.push(inf.span); - tcx.ty_error().into() + tcx.const_error(ty).into() } } _ => unreachable!(), diff --git a/src/test/ui/const-generics/generic_arg_infer/issue-91614.rs b/src/test/ui/const-generics/generic_arg_infer/issue-91614.rs new file mode 100644 index 0000000000000..413cc1539248a --- /dev/null +++ b/src/test/ui/const-generics/generic_arg_infer/issue-91614.rs @@ -0,0 +1,8 @@ +#![feature(portable_simd)] +#![feature(generic_arg_infer)] +use std::simd::Mask; + +fn main() { + let y = Mask::<_, _>::splat(false); + //~^ error: type annotations needed for `Mask<_, {_: usize}>` +} diff --git a/src/test/ui/const-generics/generic_arg_infer/issue-91614.stderr b/src/test/ui/const-generics/generic_arg_infer/issue-91614.stderr new file mode 100644 index 0000000000000..71a5ff79280fd --- /dev/null +++ b/src/test/ui/const-generics/generic_arg_infer/issue-91614.stderr @@ -0,0 +1,18 @@ +error[E0283]: type annotations needed for `Mask<_, {_: usize}>` + --> $DIR/issue-91614.rs:6:13 + | +LL | let y = Mask::<_, _>::splat(false); + | - ^^^^^^^^^^^^^^^^^^^ cannot infer type for type parameter `T` + | | + | consider giving `y` the explicit type `Mask<_, LANES>`, where the type parameter `T` is specified + | + = note: cannot satisfy `_: MaskElement` +note: required by a bound in `Mask::::splat` + --> $SRC_DIR/core/src/../../portable-simd/crates/core_simd/src/masks.rs:LL:COL + | +LL | T: MaskElement, + | ^^^^^^^^^^^ required by this bound in `Mask::::splat` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0283`. From 6c795951346b846964fb031df07fba2d2cd8c7d0 Mon Sep 17 00:00:00 2001 From: Ellen Date: Mon, 13 Dec 2021 03:33:14 +0000 Subject: [PATCH 05/10] extra test for bug i found --- .../generic_arg_infer/dont-use-defaults.rs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 src/test/ui/const-generics/generic_arg_infer/dont-use-defaults.rs diff --git a/src/test/ui/const-generics/generic_arg_infer/dont-use-defaults.rs b/src/test/ui/const-generics/generic_arg_infer/dont-use-defaults.rs new file mode 100644 index 0000000000000..251160a0f5f29 --- /dev/null +++ b/src/test/ui/const-generics/generic_arg_infer/dont-use-defaults.rs @@ -0,0 +1,15 @@ +// run-pass +#![feature(generic_arg_infer)] + +// test that we dont use defaults to aide in type inference + +struct Foo; +impl Foo { + fn make_arr() -> [(); N] { + [(); N] + } +} + +fn main() { + let [(), (), ()] = Foo::<_>::make_arr(); +} From da472a5a8461325140be41b6b6342192429003df Mon Sep 17 00:00:00 2001 From: Jacob Hoffman-Andrews Date: Wed, 8 Dec 2021 23:39:42 -0800 Subject: [PATCH 06/10] Add -webkit-appearance: none to search input This fixes an issue when displaying on iPad, where the search box had no borders. --- src/librustdoc/html/static/css/rustdoc.css | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css index fceb508bc4ff5..5694ba423bd99 100644 --- a/src/librustdoc/html/static/css/rustdoc.css +++ b/src/librustdoc/html/static/css/rustdoc.css @@ -836,6 +836,10 @@ h2.small-section-header > .anchor { top: 10px; } .search-input { + /* Override Normalize.css: it has a rule that sets + -webkit-appearance: textfield for search inputs. That + causes rounded corners and no border on iOS Safari. */ + -webkit-appearance: none; /* Override Normalize.css: we have margins and do not want to overflow - the `moz` attribute is necessary until Firefox 29, too early to drop at this point */ From 8a28c172a128dee00debcf828e2243e94d56fb5f Mon Sep 17 00:00:00 2001 From: Jack Huey <31162821+jackh726@users.noreply.github.com> Date: Sun, 12 Dec 2021 23:23:55 -0500 Subject: [PATCH 07/10] Instead of checking for exact bounds, try to prove them --- .../rustc_infer/src/infer/free_regions.rs | 2 +- .../src/infer/lexical_region_resolve/mod.rs | 2 +- compiler/rustc_typeck/src/check/wfcheck.rs | 137 +++++++++++++----- .../generic-associated-types/issue-86787.rs | 2 +- .../issue-86787.stderr | 7 +- .../self-outlives-lint.rs | 45 ++++-- .../self-outlives-lint.stderr | 95 +++++++++--- 7 files changed, 213 insertions(+), 77 deletions(-) diff --git a/compiler/rustc_infer/src/infer/free_regions.rs b/compiler/rustc_infer/src/infer/free_regions.rs index 4814b65e320ab..e93cdf7942118 100644 --- a/compiler/rustc_infer/src/infer/free_regions.rs +++ b/compiler/rustc_infer/src/infer/free_regions.rs @@ -11,7 +11,7 @@ use rustc_middle::ty::{self, Lift, Region, TyCtxt}; /// /// This stuff is a bit convoluted and should be refactored, but as we /// transition to NLL, it'll all go away anyhow. -pub struct RegionRelations<'a, 'tcx> { +pub(crate) struct RegionRelations<'a, 'tcx> { pub tcx: TyCtxt<'tcx>, /// The context used for debug messages diff --git a/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs b/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs index 85ee6d2cdc282..a5ec84a4f1446 100644 --- a/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs +++ b/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs @@ -28,7 +28,7 @@ use std::fmt; /// assuming such values can be found. It returns the final values of /// all the variables as well as a set of errors that must be reported. #[instrument(level = "debug", skip(region_rels, var_infos, data))] -pub fn resolve<'tcx>( +pub(crate) fn resolve<'tcx>( region_rels: &RegionRelations<'_, 'tcx>, var_infos: VarInfos, data: RegionConstraintData<'tcx>, diff --git a/compiler/rustc_typeck/src/check/wfcheck.rs b/compiler/rustc_typeck/src/check/wfcheck.rs index 3fd3284d8b101..6fba3d3ad08df 100644 --- a/compiler/rustc_typeck/src/check/wfcheck.rs +++ b/compiler/rustc_typeck/src/check/wfcheck.rs @@ -14,8 +14,9 @@ use rustc_hir::lang_items::LangItem; use rustc_hir::ItemKind; use rustc_infer::infer::outlives::env::OutlivesEnvironment; use rustc_infer::infer::outlives::obligations::TypeOutlives; -use rustc_infer::infer::TyCtxtInferExt; use rustc_infer::infer::{self, RegionckMode, SubregionOrigin}; +use rustc_infer::infer::{RegionResolutionError, TyCtxtInferExt}; +use rustc_infer::traits::TraitEngine; use rustc_middle::hir::map as hir_map; use rustc_middle::ty::subst::{GenericArgKind, InternalSubsts, Subst}; use rustc_middle::ty::trait_def::TraitSpecializationKind; @@ -26,7 +27,9 @@ use rustc_session::parse::feature_err; use rustc_span::symbol::{sym, Ident, Symbol}; use rustc_span::{Span, DUMMY_SP}; use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _; -use rustc_trait_selection::traits::{self, ObligationCause, ObligationCauseCode, WellFormedLoc}; +use rustc_trait_selection::traits::{ + self, ObligationCause, ObligationCauseCode, TraitEngineExt, WellFormedLoc, +}; use std::convert::TryInto; use std::iter; @@ -426,42 +429,105 @@ fn check_gat_where_clauses( } } - // If there are any missing clauses, emit an error - let mut clauses = clauses.unwrap_or_default(); + // If there are any clauses that aren't provable, emit an error + let clauses = clauses.unwrap_or_default(); debug!(?clauses); if !clauses.is_empty() { - let written_predicates: ty::GenericPredicates<'_> = - tcx.explicit_predicates_of(trait_item.def_id); - let mut clauses: Vec<_> = clauses - .drain_filter(|clause| !written_predicates.predicates.iter().any(|p| &p.0 == clause)) - .map(|clause| format!("{}", clause)) - .collect(); - // We sort so that order is predictable - clauses.sort(); - if !clauses.is_empty() { - let mut err = tcx.sess.struct_span_err( - trait_item.span, - &format!("Missing required bounds on {}", trait_item.ident), - ); + let param_env = tcx.param_env(trait_item.def_id); - let suggestion = format!( - "{} {}", - if !trait_item.generics.where_clause.predicates.is_empty() { - "," - } else { - " where" - }, - clauses.join(", "), - ); - err.span_suggestion( - trait_item.generics.where_clause.tail_span_for_suggestion(), - "add the required where clauses", - suggestion, - Applicability::MachineApplicable, - ); + // This shouldn't really matter, but we need it + let cause = traits::ObligationCause::new( + trait_item.span, + trait_item.hir_id(), + ObligationCauseCode::MiscObligation, + ); + // Create an `InferCtxt` to try to prove the clauses we require + tcx.infer_ctxt().enter(|infcx| { + let mut fulfillment_cx = >::new(tcx); + + // Register all the clauses as obligations + clauses + .clone() + .into_iter() + .map(|predicate| { + traits::Obligation::new( + cause.clone(), + param_env, + predicate, + ) + }) + .for_each(|obligation| { + fulfillment_cx.register_predicate_obligation(&infcx, obligation) + }); + + // Convert these obligations into constraints by selecting + let errors = fulfillment_cx.select_all_or_error(&infcx); + if !errors.is_empty() { + bug!("should have only registered region obligations, which get registerd as constraints"); + } - err.emit() - } + // FIXME(jackh726): some of this code is shared with `regionctxt`, but in a different + // flow; we could probably better extract the shared logic + + // Process the region obligations + let body_id_map = infcx + .inner + .borrow() + .region_obligations() + .iter() + .map(|&(id, _)| (id, vec![])) + .collect(); + + infcx.process_registered_region_obligations(&body_id_map, None, param_env); + + // Resolve the region constraints to find any constraints that we're provable + let outlives_env = OutlivesEnvironment::new(param_env); + let errors = infcx.resolve_regions(trait_item.def_id.to_def_id(), &outlives_env, RegionckMode::default()); + + // Emit an error if there are non-provable constriants + if !errors.is_empty() { + let mut clauses: Vec<_> = errors.into_iter().map(|error| match error { + RegionResolutionError::ConcreteFailure(_, sup, sub) => format!("{}: {}", sub, sup), + RegionResolutionError::GenericBoundFailure(_, sub, sup) => format!("{}: {}", sub, sup), + _ => bug!("Unexpected region resolution error when resolving outlives lint"), + }).collect(); + clauses.sort(); + + let plural = if clauses.len() > 1 { "s" } else { "" }; + let mut err = tcx.sess.struct_span_err( + trait_item.span, + &format!("missing required bound{} on `{}`", plural, trait_item.ident), + ); + + let suggestion = format!( + "{} {}", + if !trait_item.generics.where_clause.predicates.is_empty() { + "," + } else { + " where" + }, + clauses.join(", "), + ); + err.span_suggestion( + trait_item.generics.where_clause.tail_span_for_suggestion(), + &format!("add the required where clause{}", plural), + suggestion, + Applicability::MachineApplicable, + ); + + let bound = if clauses.len() > 1 { "these bounds are" } else { "this bound is" }; + err.note( + &format!("{} required to ensure that impls have maximum flexibility", bound) + ); + err.note( + "see issue #87479 \ + \ + for more information", + ); + + err.emit() + } + }); } } @@ -541,7 +607,8 @@ fn region_known_to_outlive<'tcx>( }); use rustc_infer::infer::outlives::obligations::TypeOutlivesDelegate; - (&infcx).push_sub_region_constraint(origin, region_a, region_b); + // `region_a: region_b` -> `region_b <= region_a` + (&infcx).push_sub_region_constraint(origin, region_b, region_a); let errors = infcx.resolve_regions( id.expect_owner().to_def_id(), diff --git a/src/test/ui/generic-associated-types/issue-86787.rs b/src/test/ui/generic-associated-types/issue-86787.rs index 0f62f83e2563b..5863bac2f9d0b 100644 --- a/src/test/ui/generic-associated-types/issue-86787.rs +++ b/src/test/ui/generic-associated-types/issue-86787.rs @@ -9,7 +9,7 @@ enum Either { pub trait HasChildrenOf { type T; type TRef<'a>; - //~^ Missing required bounds + //~^ missing required fn ref_children<'a>(&'a self) -> Vec>; fn take_children(self) -> Vec; diff --git a/src/test/ui/generic-associated-types/issue-86787.stderr b/src/test/ui/generic-associated-types/issue-86787.stderr index 87dcd875de703..18b1c22685b0c 100644 --- a/src/test/ui/generic-associated-types/issue-86787.stderr +++ b/src/test/ui/generic-associated-types/issue-86787.stderr @@ -1,10 +1,13 @@ -error: Missing required bounds on TRef +error: missing required bound on `TRef` --> $DIR/issue-86787.rs:11:5 | LL | type TRef<'a>; | ^^^^^^^^^^^^^- | | - | help: add the required where clauses: `where Self: 'a` + | help: add the required where clause: `where Self: 'a` + | + = note: this bound is required to ensure that impls have maximum flexibility + = note: see issue #87479 for more information error: aborting due to previous error diff --git a/src/test/ui/generic-associated-types/self-outlives-lint.rs b/src/test/ui/generic-associated-types/self-outlives-lint.rs index af90d158855d8..37b3a6155d5ae 100644 --- a/src/test/ui/generic-associated-types/self-outlives-lint.rs +++ b/src/test/ui/generic-associated-types/self-outlives-lint.rs @@ -7,7 +7,7 @@ use std::fmt::Debug; // We have a `&'a self`, so we need a `Self: 'a` trait Iterable { type Item<'x>; - //~^ Missing required bounds + //~^ missing required fn iter<'a>(&'a self) -> Self::Item<'a>; } @@ -23,7 +23,7 @@ impl Iterable for T { // We have a `&'a T`, so we need a `T: 'x` trait Deserializer { type Out<'x>; - //~^ Missing required bounds + //~^ missing required fn deserialize<'a>(&self, input: &'a T) -> Self::Out<'a>; } @@ -37,14 +37,14 @@ impl Deserializer for () { // We have a `&'b T` and a `'b: 'a`, so it is implied that `T: 'a`. Therefore, we need a `T: 'x` trait Deserializer2 { type Out<'x>; - //~^ Missing required bounds + //~^ missing required fn deserialize2<'a, 'b: 'a>(&self, input1: &'b T) -> Self::Out<'a>; } // We have a `&'a T` and a `&'b U`, so we need a `T: 'x` and a `U: 'y` trait Deserializer3 { type Out<'x, 'y>; - //~^ Missing required bounds + //~^ missing required fn deserialize2<'a, 'b>(&self, input: &'a T, input2: &'b U) -> Self::Out<'a, 'b>; } @@ -59,7 +59,7 @@ struct Wrap(T); // We pass `Wrap` and we see `&'z Wrap`, so we require `D: 'x` trait Des { type Out<'x, D>; - //~^ Missing required bounds + //~^ missing required fn des<'z, T>(&self, data: &'z Wrap) -> Self::Out<'z, Wrap>; } /* @@ -75,7 +75,7 @@ impl Des for () { // implied bound that `T: 'z`, so we require `D: 'x` trait Des2 { type Out<'x, D>; - //~^ Missing required bounds + //~^ missing required fn des<'z, T>(&self, data: &'z Wrap) -> Self::Out<'z, T>; } /* @@ -90,7 +90,7 @@ impl Des2 for () { // We see `&'z T`, so we require `D: 'x` trait Des3 { type Out<'x, D>; - //~^ Missing required bounds + //~^ missing required fn des<'z, T>(&self, data: &'z T) -> Self::Out<'z, T>; } /* @@ -112,7 +112,7 @@ trait NoGat<'a> { // FIXME: we require two bounds (`where Self: 'a, Self: 'b`) when we should only require one trait TraitLifetime<'a> { type Bar<'b>; - //~^ Missing required bounds + //~^ missing required fn method(&'a self) -> Self::Bar<'a>; } @@ -120,14 +120,14 @@ trait TraitLifetime<'a> { // FIXME: we require two bounds (`where Self: 'a, Self: 'b`) when we should only require one trait TraitLifetimeWhere<'a> where Self: 'a { type Bar<'b>; - //~^ Missing required bounds + //~^ missing required fn method(&'a self) -> Self::Bar<'a>; } // Explicit bound instead of implicit; we want to still error trait ExplicitBound { type Bar<'b>; - //~^ Missing required bounds + //~^ missing required fn method<'b>(&self, token: &'b ()) -> Self::Bar<'b> where Self: 'b; } @@ -141,14 +141,15 @@ trait NotInReturn { trait IterableTwo { type Item<'a>; type Iterator<'a>: Iterator>; - //~^ Missing required bounds + //~^ missing required fn iter<'a>(&'a self) -> Self::Iterator<'a>; } -// We also should report region outlives clauses +// We also should report region outlives clauses. Here, we know that `'y: 'x`, +// because of `&'x &'y`, so we require that `'b: 'a`. trait RegionOutlives { type Bar<'a, 'b>; - //~^ Missing required bounds + //~^ missing required fn foo<'x, 'y>(&self, input: &'x &'y ()) -> Self::Bar<'x, 'y>; } @@ -161,6 +162,17 @@ impl Foo for () { } */ +// Similar to the above, except with explicit bounds +trait ExplicitRegionOutlives<'ctx> { + type Fut<'out>; + //~^ missing required + + fn test<'out>(ctx: &'ctx i32) -> Self::Fut<'out> + where + 'ctx: 'out; +} + + // If there are multiple methods that return the GAT, require a set of clauses // that can be satisfied by *all* methods trait MultipleMethods { @@ -170,4 +182,11 @@ trait MultipleMethods { fn gimme_default(&self) -> Self::Bar<'static>; } +// We would normally require `Self: 'a`, but we can prove that `Self: 'static` +// because of the the bounds on the trait, so the bound is proven +trait Trait: 'static { + type Assoc<'a>; + fn make_assoc(_: &u32) -> Self::Assoc<'_>; +} + fn main() {} diff --git a/src/test/ui/generic-associated-types/self-outlives-lint.stderr b/src/test/ui/generic-associated-types/self-outlives-lint.stderr index bf85780f69f7a..c82dcdae20479 100644 --- a/src/test/ui/generic-associated-types/self-outlives-lint.stderr +++ b/src/test/ui/generic-associated-types/self-outlives-lint.stderr @@ -1,98 +1,145 @@ -error: Missing required bounds on Item +error: missing required bound on `Item` --> $DIR/self-outlives-lint.rs:9:5 | LL | type Item<'x>; | ^^^^^^^^^^^^^- | | - | help: add the required where clauses: `where Self: 'x` + | help: add the required where clause: `where Self: 'x` + | + = note: this bound is required to ensure that impls have maximum flexibility + = note: see issue #87479 for more information -error: Missing required bounds on Out +error: missing required bound on `Out` --> $DIR/self-outlives-lint.rs:25:5 | LL | type Out<'x>; | ^^^^^^^^^^^^- | | - | help: add the required where clauses: `where T: 'x` + | help: add the required where clause: `where T: 'x` + | + = note: this bound is required to ensure that impls have maximum flexibility + = note: see issue #87479 for more information -error: Missing required bounds on Out +error: missing required bound on `Out` --> $DIR/self-outlives-lint.rs:39:5 | LL | type Out<'x>; | ^^^^^^^^^^^^- | | - | help: add the required where clauses: `where T: 'x` + | help: add the required where clause: `where T: 'x` + | + = note: this bound is required to ensure that impls have maximum flexibility + = note: see issue #87479 for more information -error: Missing required bounds on Out +error: missing required bounds on `Out` --> $DIR/self-outlives-lint.rs:46:5 | LL | type Out<'x, 'y>; | ^^^^^^^^^^^^^^^^- | | | help: add the required where clauses: `where T: 'x, U: 'y` + | + = note: these bounds are required to ensure that impls have maximum flexibility + = note: see issue #87479 for more information -error: Missing required bounds on Out +error: missing required bound on `Out` --> $DIR/self-outlives-lint.rs:61:5 | LL | type Out<'x, D>; | ^^^^^^^^^^^^^^^- | | - | help: add the required where clauses: `where D: 'x` + | help: add the required where clause: `where D: 'x` + | + = note: this bound is required to ensure that impls have maximum flexibility + = note: see issue #87479 for more information -error: Missing required bounds on Out +error: missing required bound on `Out` --> $DIR/self-outlives-lint.rs:77:5 | LL | type Out<'x, D>; | ^^^^^^^^^^^^^^^- | | - | help: add the required where clauses: `where D: 'x` + | help: add the required where clause: `where D: 'x` + | + = note: this bound is required to ensure that impls have maximum flexibility + = note: see issue #87479 for more information -error: Missing required bounds on Out +error: missing required bound on `Out` --> $DIR/self-outlives-lint.rs:92:5 | LL | type Out<'x, D>; | ^^^^^^^^^^^^^^^- | | - | help: add the required where clauses: `where D: 'x` + | help: add the required where clause: `where D: 'x` + | + = note: this bound is required to ensure that impls have maximum flexibility + = note: see issue #87479 for more information -error: Missing required bounds on Bar +error: missing required bounds on `Bar` --> $DIR/self-outlives-lint.rs:114:5 | LL | type Bar<'b>; | ^^^^^^^^^^^^- | | | help: add the required where clauses: `where Self: 'a, Self: 'b` + | + = note: these bounds are required to ensure that impls have maximum flexibility + = note: see issue #87479 for more information -error: Missing required bounds on Bar +error: missing required bound on `Bar` --> $DIR/self-outlives-lint.rs:122:5 | LL | type Bar<'b>; | ^^^^^^^^^^^^- | | - | help: add the required where clauses: `where Self: 'a, Self: 'b` + | help: add the required where clause: `where Self: 'b` + | + = note: this bound is required to ensure that impls have maximum flexibility + = note: see issue #87479 for more information -error: Missing required bounds on Bar +error: missing required bound on `Bar` --> $DIR/self-outlives-lint.rs:129:5 | LL | type Bar<'b>; | ^^^^^^^^^^^^- | | - | help: add the required where clauses: `where Self: 'b` + | help: add the required where clause: `where Self: 'b` + | + = note: this bound is required to ensure that impls have maximum flexibility + = note: see issue #87479 for more information -error: Missing required bounds on Iterator +error: missing required bound on `Iterator` --> $DIR/self-outlives-lint.rs:143:5 | LL | type Iterator<'a>: Iterator>; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- | | - | help: add the required where clauses: `where Self: 'a` + | help: add the required where clause: `where Self: 'a` + | + = note: this bound is required to ensure that impls have maximum flexibility + = note: see issue #87479 for more information -error: Missing required bounds on Bar - --> $DIR/self-outlives-lint.rs:150:5 +error: missing required bound on `Bar` + --> $DIR/self-outlives-lint.rs:151:5 | LL | type Bar<'a, 'b>; | ^^^^^^^^^^^^^^^^- | | - | help: add the required where clauses: `where 'a: 'b` + | help: add the required where clause: `where 'b: 'a` + | + = note: this bound is required to ensure that impls have maximum flexibility + = note: see issue #87479 for more information + +error: missing required bound on `Fut` + --> $DIR/self-outlives-lint.rs:167:5 + | +LL | type Fut<'out>; + | ^^^^^^^^^^^^^^- + | | + | help: add the required where clause: `where 'ctx: 'out` + | + = note: this bound is required to ensure that impls have maximum flexibility + = note: see issue #87479 for more information -error: aborting due to 12 previous errors +error: aborting due to 13 previous errors From 7cbd0dcf9372814cacc43d1860fce8bd36c44489 Mon Sep 17 00:00:00 2001 From: Jack Huey <31162821+jackh726@users.noreply.github.com> Date: Mon, 13 Dec 2021 01:10:39 -0500 Subject: [PATCH 08/10] I wrote these functions, I should use them dang it --- compiler/rustc_typeck/src/check/wfcheck.rs | 152 ++++++++------------- 1 file changed, 60 insertions(+), 92 deletions(-) diff --git a/compiler/rustc_typeck/src/check/wfcheck.rs b/compiler/rustc_typeck/src/check/wfcheck.rs index 6fba3d3ad08df..3576764596cc5 100644 --- a/compiler/rustc_typeck/src/check/wfcheck.rs +++ b/compiler/rustc_typeck/src/check/wfcheck.rs @@ -14,9 +14,8 @@ use rustc_hir::lang_items::LangItem; use rustc_hir::ItemKind; use rustc_infer::infer::outlives::env::OutlivesEnvironment; use rustc_infer::infer::outlives::obligations::TypeOutlives; +use rustc_infer::infer::TyCtxtInferExt; use rustc_infer::infer::{self, RegionckMode, SubregionOrigin}; -use rustc_infer::infer::{RegionResolutionError, TyCtxtInferExt}; -use rustc_infer::traits::TraitEngine; use rustc_middle::hir::map as hir_map; use rustc_middle::ty::subst::{GenericArgKind, InternalSubsts, Subst}; use rustc_middle::ty::trait_def::TraitSpecializationKind; @@ -27,9 +26,7 @@ use rustc_session::parse::feature_err; use rustc_span::symbol::{sym, Ident, Symbol}; use rustc_span::{Span, DUMMY_SP}; use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _; -use rustc_trait_selection::traits::{ - self, ObligationCause, ObligationCauseCode, TraitEngineExt, WellFormedLoc, -}; +use rustc_trait_selection::traits::{self, ObligationCause, ObligationCauseCode, WellFormedLoc}; use std::convert::TryInto; use std::iter; @@ -435,99 +432,70 @@ fn check_gat_where_clauses( if !clauses.is_empty() { let param_env = tcx.param_env(trait_item.def_id); - // This shouldn't really matter, but we need it - let cause = traits::ObligationCause::new( - trait_item.span, - trait_item.hir_id(), - ObligationCauseCode::MiscObligation, - ); - // Create an `InferCtxt` to try to prove the clauses we require - tcx.infer_ctxt().enter(|infcx| { - let mut fulfillment_cx = >::new(tcx); - - // Register all the clauses as obligations - clauses - .clone() - .into_iter() - .map(|predicate| { - traits::Obligation::new( - cause.clone(), + let mut clauses: Vec<_> = clauses + .into_iter() + .filter(|clause| match clause.kind().skip_binder() { + ty::PredicateKind::RegionOutlives(ty::OutlivesPredicate(a, b)) => { + !region_known_to_outlive( + tcx, + trait_item.hir_id(), param_env, - predicate, + &FxHashSet::default(), + a, + b, ) - }) - .for_each(|obligation| { - fulfillment_cx.register_predicate_obligation(&infcx, obligation) - }); - - // Convert these obligations into constraints by selecting - let errors = fulfillment_cx.select_all_or_error(&infcx); - if !errors.is_empty() { - bug!("should have only registered region obligations, which get registerd as constraints"); - } + } + ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(a, b)) => { + !ty_known_to_outlive( + tcx, + trait_item.hir_id(), + param_env, + &FxHashSet::default(), + a, + b, + ) + } + _ => bug!("Unexpected PredicateKind"), + }) + .map(|clause| format!("{}", clause)) + .collect(); - // FIXME(jackh726): some of this code is shared with `regionctxt`, but in a different - // flow; we could probably better extract the shared logic - - // Process the region obligations - let body_id_map = infcx - .inner - .borrow() - .region_obligations() - .iter() - .map(|&(id, _)| (id, vec![])) - .collect(); - - infcx.process_registered_region_obligations(&body_id_map, None, param_env); - - // Resolve the region constraints to find any constraints that we're provable - let outlives_env = OutlivesEnvironment::new(param_env); - let errors = infcx.resolve_regions(trait_item.def_id.to_def_id(), &outlives_env, RegionckMode::default()); - - // Emit an error if there are non-provable constriants - if !errors.is_empty() { - let mut clauses: Vec<_> = errors.into_iter().map(|error| match error { - RegionResolutionError::ConcreteFailure(_, sup, sub) => format!("{}: {}", sub, sup), - RegionResolutionError::GenericBoundFailure(_, sub, sup) => format!("{}: {}", sub, sup), - _ => bug!("Unexpected region resolution error when resolving outlives lint"), - }).collect(); - clauses.sort(); - - let plural = if clauses.len() > 1 { "s" } else { "" }; - let mut err = tcx.sess.struct_span_err( - trait_item.span, - &format!("missing required bound{} on `{}`", plural, trait_item.ident), - ); + // We sort so that order is predictable + clauses.sort(); - let suggestion = format!( - "{} {}", - if !trait_item.generics.where_clause.predicates.is_empty() { - "," - } else { - " where" - }, - clauses.join(", "), - ); - err.span_suggestion( - trait_item.generics.where_clause.tail_span_for_suggestion(), - &format!("add the required where clause{}", plural), - suggestion, - Applicability::MachineApplicable, - ); + if !clauses.is_empty() { + let plural = if clauses.len() > 1 { "s" } else { "" }; + let mut err = tcx.sess.struct_span_err( + trait_item.span, + &format!("missing required bound{} on `{}`", plural, trait_item.ident), + ); - let bound = if clauses.len() > 1 { "these bounds are" } else { "this bound is" }; - err.note( - &format!("{} required to ensure that impls have maximum flexibility", bound) - ); - err.note( - "see issue #87479 \ - \ - for more information", - ); + let suggestion = format!( + "{} {}", + if !trait_item.generics.where_clause.predicates.is_empty() { + "," + } else { + " where" + }, + clauses.join(", "), + ); + err.span_suggestion( + trait_item.generics.where_clause.tail_span_for_suggestion(), + &format!("add the required where clause{}", plural), + suggestion, + Applicability::MachineApplicable, + ); - err.emit() - } - }); + let bound = if clauses.len() > 1 { "these bounds are" } else { "this bound is" }; + err.note(&format!("{} required to ensure that impls have maximum flexibility", bound)); + err.note( + "see issue #87479 \ + \ + for more information", + ); + + err.emit() + } } } From 23e4aeb14067b401bc2d11a4bbdb035ee7a4c81a Mon Sep 17 00:00:00 2001 From: Konrad Borowski Date: Mon, 13 Dec 2021 08:43:19 +0100 Subject: [PATCH 09/10] Stabilize const_cstr_unchecked --- compiler/rustc_codegen_llvm/src/lib.rs | 1 - library/std/src/ffi/c_str.rs | 2 +- library/std/src/lib.rs | 1 - 3 files changed, 1 insertion(+), 3 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs index 62c17e6a10f17..1dfaae7a1504f 100644 --- a/compiler/rustc_codegen_llvm/src/lib.rs +++ b/compiler/rustc_codegen_llvm/src/lib.rs @@ -6,7 +6,6 @@ #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![feature(bool_to_option)] -#![feature(const_cstr_unchecked)] #![feature(crate_visibility_modifier)] #![feature(extern_types)] #![feature(in_band_lifetimes)] diff --git a/library/std/src/ffi/c_str.rs b/library/std/src/ffi/c_str.rs index 465bbae8631c5..9c1b79d696697 100644 --- a/library/std/src/ffi/c_str.rs +++ b/library/std/src/ffi/c_str.rs @@ -1259,7 +1259,7 @@ impl CStr { #[inline] #[must_use] #[stable(feature = "cstr_from_bytes", since = "1.10.0")] - #[rustc_const_unstable(feature = "const_cstr_unchecked", issue = "90343")] + #[rustc_const_stable(feature = "const_cstr_unchecked", since = "1.59.0")] pub const unsafe fn from_bytes_with_nul_unchecked(bytes: &[u8]) -> &CStr { // SAFETY: Casting to CStr is safe because its internal representation // is a [u8] too (safe only inside std). diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index d4ff642cd133a..dabab667ee968 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -252,7 +252,6 @@ #![feature(char_internals)] #![cfg_attr(not(bootstrap), feature(concat_bytes))] #![feature(concat_idents)] -#![feature(const_cstr_unchecked)] #![feature(const_fn_floating_point_arithmetic)] #![feature(const_fn_fn_ptr_basics)] #![feature(const_fn_trait_bound)] From 48974158f1ce88dca7edd66c7bae81e759c2679d Mon Sep 17 00:00:00 2001 From: Jack Huey <31162821+jackh726@users.noreply.github.com> Date: Mon, 13 Dec 2021 10:06:57 -0500 Subject: [PATCH 10/10] Adjust wording for review --- compiler/rustc_typeck/src/check/wfcheck.rs | 7 ++- .../issue-86787.stderr | 4 +- .../self-outlives-lint.stderr | 52 +++++++++---------- 3 files changed, 33 insertions(+), 30 deletions(-) diff --git a/compiler/rustc_typeck/src/check/wfcheck.rs b/compiler/rustc_typeck/src/check/wfcheck.rs index 3576764596cc5..1404bc271673e 100644 --- a/compiler/rustc_typeck/src/check/wfcheck.rs +++ b/compiler/rustc_typeck/src/check/wfcheck.rs @@ -487,9 +487,12 @@ fn check_gat_where_clauses( ); let bound = if clauses.len() > 1 { "these bounds are" } else { "this bound is" }; - err.note(&format!("{} required to ensure that impls have maximum flexibility", bound)); + err.note(&format!( + "{} currently required to ensure that impls have maximum flexibility", + bound + )); err.note( - "see issue #87479 \ + "we are soliciting feedback, see issue #87479 \ \ for more information", ); diff --git a/src/test/ui/generic-associated-types/issue-86787.stderr b/src/test/ui/generic-associated-types/issue-86787.stderr index 18b1c22685b0c..d4b2267d3ddc7 100644 --- a/src/test/ui/generic-associated-types/issue-86787.stderr +++ b/src/test/ui/generic-associated-types/issue-86787.stderr @@ -6,8 +6,8 @@ LL | type TRef<'a>; | | | help: add the required where clause: `where Self: 'a` | - = note: this bound is required to ensure that impls have maximum flexibility - = note: see issue #87479 for more information + = note: this bound is currently required to ensure that impls have maximum flexibility + = note: we are soliciting feedback, see issue #87479 for more information error: aborting due to previous error diff --git a/src/test/ui/generic-associated-types/self-outlives-lint.stderr b/src/test/ui/generic-associated-types/self-outlives-lint.stderr index c82dcdae20479..3b9146ad875a3 100644 --- a/src/test/ui/generic-associated-types/self-outlives-lint.stderr +++ b/src/test/ui/generic-associated-types/self-outlives-lint.stderr @@ -6,8 +6,8 @@ LL | type Item<'x>; | | | help: add the required where clause: `where Self: 'x` | - = note: this bound is required to ensure that impls have maximum flexibility - = note: see issue #87479 for more information + = note: this bound is currently required to ensure that impls have maximum flexibility + = note: we are soliciting feedback, see issue #87479 for more information error: missing required bound on `Out` --> $DIR/self-outlives-lint.rs:25:5 @@ -17,8 +17,8 @@ LL | type Out<'x>; | | | help: add the required where clause: `where T: 'x` | - = note: this bound is required to ensure that impls have maximum flexibility - = note: see issue #87479 for more information + = note: this bound is currently required to ensure that impls have maximum flexibility + = note: we are soliciting feedback, see issue #87479 for more information error: missing required bound on `Out` --> $DIR/self-outlives-lint.rs:39:5 @@ -28,8 +28,8 @@ LL | type Out<'x>; | | | help: add the required where clause: `where T: 'x` | - = note: this bound is required to ensure that impls have maximum flexibility - = note: see issue #87479 for more information + = note: this bound is currently required to ensure that impls have maximum flexibility + = note: we are soliciting feedback, see issue #87479 for more information error: missing required bounds on `Out` --> $DIR/self-outlives-lint.rs:46:5 @@ -39,8 +39,8 @@ LL | type Out<'x, 'y>; | | | help: add the required where clauses: `where T: 'x, U: 'y` | - = note: these bounds are required to ensure that impls have maximum flexibility - = note: see issue #87479 for more information + = note: these bounds are currently required to ensure that impls have maximum flexibility + = note: we are soliciting feedback, see issue #87479 for more information error: missing required bound on `Out` --> $DIR/self-outlives-lint.rs:61:5 @@ -50,8 +50,8 @@ LL | type Out<'x, D>; | | | help: add the required where clause: `where D: 'x` | - = note: this bound is required to ensure that impls have maximum flexibility - = note: see issue #87479 for more information + = note: this bound is currently required to ensure that impls have maximum flexibility + = note: we are soliciting feedback, see issue #87479 for more information error: missing required bound on `Out` --> $DIR/self-outlives-lint.rs:77:5 @@ -61,8 +61,8 @@ LL | type Out<'x, D>; | | | help: add the required where clause: `where D: 'x` | - = note: this bound is required to ensure that impls have maximum flexibility - = note: see issue #87479 for more information + = note: this bound is currently required to ensure that impls have maximum flexibility + = note: we are soliciting feedback, see issue #87479 for more information error: missing required bound on `Out` --> $DIR/self-outlives-lint.rs:92:5 @@ -72,8 +72,8 @@ LL | type Out<'x, D>; | | | help: add the required where clause: `where D: 'x` | - = note: this bound is required to ensure that impls have maximum flexibility - = note: see issue #87479 for more information + = note: this bound is currently required to ensure that impls have maximum flexibility + = note: we are soliciting feedback, see issue #87479 for more information error: missing required bounds on `Bar` --> $DIR/self-outlives-lint.rs:114:5 @@ -83,8 +83,8 @@ LL | type Bar<'b>; | | | help: add the required where clauses: `where Self: 'a, Self: 'b` | - = note: these bounds are required to ensure that impls have maximum flexibility - = note: see issue #87479 for more information + = note: these bounds are currently required to ensure that impls have maximum flexibility + = note: we are soliciting feedback, see issue #87479 for more information error: missing required bound on `Bar` --> $DIR/self-outlives-lint.rs:122:5 @@ -94,8 +94,8 @@ LL | type Bar<'b>; | | | help: add the required where clause: `where Self: 'b` | - = note: this bound is required to ensure that impls have maximum flexibility - = note: see issue #87479 for more information + = note: this bound is currently required to ensure that impls have maximum flexibility + = note: we are soliciting feedback, see issue #87479 for more information error: missing required bound on `Bar` --> $DIR/self-outlives-lint.rs:129:5 @@ -105,8 +105,8 @@ LL | type Bar<'b>; | | | help: add the required where clause: `where Self: 'b` | - = note: this bound is required to ensure that impls have maximum flexibility - = note: see issue #87479 for more information + = note: this bound is currently required to ensure that impls have maximum flexibility + = note: we are soliciting feedback, see issue #87479 for more information error: missing required bound on `Iterator` --> $DIR/self-outlives-lint.rs:143:5 @@ -116,8 +116,8 @@ LL | type Iterator<'a>: Iterator>; | | | help: add the required where clause: `where Self: 'a` | - = note: this bound is required to ensure that impls have maximum flexibility - = note: see issue #87479 for more information + = note: this bound is currently required to ensure that impls have maximum flexibility + = note: we are soliciting feedback, see issue #87479 for more information error: missing required bound on `Bar` --> $DIR/self-outlives-lint.rs:151:5 @@ -127,8 +127,8 @@ LL | type Bar<'a, 'b>; | | | help: add the required where clause: `where 'b: 'a` | - = note: this bound is required to ensure that impls have maximum flexibility - = note: see issue #87479 for more information + = note: this bound is currently required to ensure that impls have maximum flexibility + = note: we are soliciting feedback, see issue #87479 for more information error: missing required bound on `Fut` --> $DIR/self-outlives-lint.rs:167:5 @@ -138,8 +138,8 @@ LL | type Fut<'out>; | | | help: add the required where clause: `where 'ctx: 'out` | - = note: this bound is required to ensure that impls have maximum flexibility - = note: see issue #87479 for more information + = note: this bound is currently required to ensure that impls have maximum flexibility + = note: we are soliciting feedback, see issue #87479 for more information error: aborting due to 13 previous errors