From f521e4185323699cd5d063b2704367a319583982 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Tue, 15 Jun 2021 21:02:40 +0300 Subject: internal: introduce minicore -- a subset of libcore for testing --- crates/test_utils/src/fixture.rs | 157 +++++++++++++++++++++++++++++++++++--- crates/test_utils/src/lib.rs | 5 +- crates/test_utils/src/minicore.rs | 69 +++++++++++++++++ 3 files changed, 221 insertions(+), 10 deletions(-) create mode 100644 crates/test_utils/src/minicore.rs (limited to 'crates/test_utils') diff --git a/crates/test_utils/src/fixture.rs b/crates/test_utils/src/fixture.rs index d0bddf7d8..535892f3f 100644 --- a/crates/test_utils/src/fixture.rs +++ b/crates/test_utils/src/fixture.rs @@ -77,6 +77,11 @@ pub struct Fixture { pub introduce_new_source_root: bool, } +pub struct MiniCore { + activated_flags: Vec, + valid_flags: Vec, +} + impl Fixture { /// Parses text which looks like this: /// @@ -86,12 +91,28 @@ impl Fixture { /// line 2 /// //- other meta /// ``` - pub fn parse(ra_fixture: &str) -> Vec { + /// + /// Fixture can also start with a minicore declaration: + /// + /// ``` + /// //- minicore: sized + /// ``` + /// + /// That will include a subset of `libcore` into the fixture, see + /// `minicore.rs` for what's available. + pub fn parse(ra_fixture: &str) -> (Option, Vec) { let fixture = trim_indent(ra_fixture); - + let mut fixture = fixture.as_str(); + let mut mini_core = None; let mut res: Vec = Vec::new(); - let default = if ra_fixture.contains("//-") { None } else { Some("//- /main.rs") }; + if fixture.starts_with("//- minicore:") { + let first_line = fixture.split_inclusive('\n').next().unwrap(); + mini_core = Some(MiniCore::parse(first_line)); + fixture = &fixture[first_line.len()..]; + } + + let default = if fixture.contains("//-") { None } else { Some("//- /main.rs") }; for (ix, line) in default.into_iter().chain(fixture.split_inclusive('\n')).enumerate() { if line.contains("//-") { @@ -113,7 +134,7 @@ impl Fixture { } } - res + (mini_core, res) } //- /lib.rs crate:foo deps:bar,baz cfg:foo=a,bar=b env:OUTDIR=path/to,OTHER=foo @@ -172,6 +193,122 @@ impl Fixture { } } +impl MiniCore { + fn has_flag(&self, flag: &str) -> bool { + self.activated_flags.iter().any(|it| it == flag) + } + + fn assert_valid_flag(&self, flag: &str) { + if !self.valid_flags.iter().any(|it| it == flag) { + panic!("invalid flag: {:?}, valid flags: {:?}", flag, self.valid_flags); + } + } + + fn parse(line: &str) -> MiniCore { + let mut res = MiniCore { activated_flags: Vec::new(), valid_flags: Vec::new() }; + + let line = line.strip_prefix("//- minicore:").unwrap().trim(); + for entry in line.split(", ") { + if res.has_flag(entry) { + panic!("duplicate minicore flag: {:?}", entry) + } + res.activated_flags.push(entry.to_string()) + } + + res + } + + /// Strips parts of minicore.rs which are flagged by inactive flags. + /// + /// This is probably over-engineered to support flags dependencies. + pub fn source_code(mut self) -> String { + let mut buf = String::new(); + let raw_mini_core = include_str!("./minicore.rs"); + let mut lines = raw_mini_core.split_inclusive('\n'); + + let mut parsing_flags = false; + let mut implications = Vec::new(); + + // Parse `//!` preamble and extract flags and dependencies. + for line in lines.by_ref() { + let line = match line.strip_prefix("//!") { + Some(it) => it, + None => { + assert!(line.trim().is_empty()); + break; + } + }; + + if parsing_flags { + let (flag, deps) = line.split_once(':').unwrap(); + let flag = flag.trim(); + self.valid_flags.push(flag.to_string()); + for dep in deps.split(", ") { + let dep = dep.trim(); + if !dep.is_empty() { + self.assert_valid_flag(dep); + implications.push((flag, dep)); + } + } + } + + if line.contains("Available flags:") { + parsing_flags = true; + } + } + + for flag in &self.activated_flags { + self.assert_valid_flag(flag); + } + + // Fixed point loop to compute transitive closure of flags. + loop { + let mut changed = false; + for &(u, v) in implications.iter() { + if self.has_flag(u) && !self.has_flag(v) { + self.activated_flags.push(v.to_string()); + changed = true; + } + } + if !changed { + break; + } + } + + let mut curr_region = ""; + for line in lines { + let trimmed = line.trim(); + if let Some(region) = trimmed.strip_prefix("// region:") { + assert_eq!(curr_region, ""); + curr_region = region; + continue; + } + if let Some(region) = trimmed.strip_prefix("// endregion:") { + assert_eq!(curr_region, region); + curr_region = ""; + continue; + } + + let mut flag = curr_region; + if let Some(idx) = trimmed.find("// :") { + flag = &trimmed[idx + "// :".len()..]; + } + + let skip = if flag == "" { + false + } else { + self.assert_valid_flag(flag); + !self.has_flag(flag) + }; + + if !skip { + buf.push_str(line) + } + } + buf + } +} + #[test] #[should_panic] fn parse_fixture_checks_further_indented_metadata() { @@ -189,12 +326,14 @@ fn parse_fixture_checks_further_indented_metadata() { #[test] fn parse_fixture_gets_full_meta() { - let parsed = Fixture::parse( - r" - //- /lib.rs crate:foo deps:bar,baz cfg:foo=a,bar=b,atom env:OUTDIR=path/to,OTHER=foo - mod m; - ", + let (mini_core, parsed) = Fixture::parse( + r#" +//- minicore: coerce_unsized +//- /lib.rs crate:foo deps:bar,baz cfg:foo=a,bar=b,atom env:OUTDIR=path/to,OTHER=foo +mod m; +"#, ); + assert_eq!(mini_core.unwrap().activated_flags, vec!["coerce_unsized".to_string()]); assert_eq!(1, parsed.len()); let meta = &parsed[0]; diff --git a/crates/test_utils/src/lib.rs b/crates/test_utils/src/lib.rs index b2fe25f82..d55bae62a 100644 --- a/crates/test_utils/src/lib.rs +++ b/crates/test_utils/src/lib.rs @@ -23,7 +23,10 @@ use text_size::{TextRange, TextSize}; pub use dissimilar::diff as __diff; pub use rustc_hash::FxHashMap; -pub use crate::{assert_linear::AssertLinear, fixture::Fixture}; +pub use crate::{ + assert_linear::AssertLinear, + fixture::{Fixture, MiniCore}, +}; pub const CURSOR_MARKER: &str = "$0"; pub const ESCAPED_CURSOR_MARKER: &str = "\\$0"; diff --git a/crates/test_utils/src/minicore.rs b/crates/test_utils/src/minicore.rs new file mode 100644 index 000000000..629c06ed0 --- /dev/null +++ b/crates/test_utils/src/minicore.rs @@ -0,0 +1,69 @@ +//! This is a fixture we use for tests that need lang items. +//! +//! We want to include the minimal subset of core for each test, so this file +//! supports "conditional compilation". Tests use the following syntax to include minicore: +//! +//! //- minicore: flag1, flag2 +//! +//! We then strip all the code marked with other flags. +//! +//! Available flags: +//! sized: +//! coerce_unsized: sized + +pub mod marker { + // region:sized + #[lang = "sized"] + #[fundamental] + #[rustc_specialization_trait] + pub trait Sized {} + + #[lang = "unsize"] + pub trait Unsize {} + // endregion:sized +} + +pub mod ops { + mod unsize { + // region:coerce_unsized + use crate::marker::Unsize; + + #[lang = "coerce_unsized"] + pub trait CoerceUnsized {} + + impl<'a, T: ?Sized + Unsize, U: ?Sized> CoerceUnsized<&'a mut U> for &'a mut T {} + impl<'a, 'b: 'a, T: ?Sized + Unsize, U: ?Sized> CoerceUnsized<&'a U> for &'b mut T {} + impl<'a, T: ?Sized + Unsize, U: ?Sized> CoerceUnsized<*mut U> for &'a mut T {} + impl<'a, T: ?Sized + Unsize, U: ?Sized> CoerceUnsized<*const U> for &'a mut T {} + + impl<'a, 'b: 'a, T: ?Sized + Unsize, U: ?Sized> CoerceUnsized<&'a U> for &'b T {} + impl<'a, T: ?Sized + Unsize, U: ?Sized> CoerceUnsized<*const U> for &'a T {} + + impl, U: ?Sized> CoerceUnsized<*mut U> for *mut T {} + impl, U: ?Sized> CoerceUnsized<*const U> for *mut T {} + impl, U: ?Sized> CoerceUnsized<*const U> for *const T {} + // endregion:coerce_unsized + } +} + +pub mod prelude { + pub mod v1 { + pub use crate::marker::Sized; // :sized + } + + pub mod rust_2015 { + pub use super::v1::*; + } + + pub mod rust_2018 { + pub use super::v1::*; + } + + pub mod rust_2021 { + pub use super::v1::*; + } +} + +#[prelude_import] +#[allow(unused)] +use prelude::v1::*; -- cgit v1.2.3 From f841369fee0f49125c83046340b228b032ebc702 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Tue, 15 Jun 2021 21:11:53 +0300 Subject: internal: switch some tests to minicore --- crates/test_utils/src/minicore.rs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'crates/test_utils') diff --git a/crates/test_utils/src/minicore.rs b/crates/test_utils/src/minicore.rs index 629c06ed0..8f8f1c9f8 100644 --- a/crates/test_utils/src/minicore.rs +++ b/crates/test_utils/src/minicore.rs @@ -9,7 +9,8 @@ //! //! Available flags: //! sized: -//! coerce_unsized: sized +//! unsize: sized +//! coerce_unsized: unsize pub mod marker { // region:sized @@ -17,10 +18,12 @@ pub mod marker { #[fundamental] #[rustc_specialization_trait] pub trait Sized {} + // endregion:sized + // region:unsize #[lang = "unsize"] pub trait Unsize {} - // endregion:sized + // endregion:unsize } pub mod ops { @@ -44,6 +47,8 @@ pub mod ops { impl, U: ?Sized> CoerceUnsized<*const U> for *const T {} // endregion:coerce_unsized } + + pub use self::unsize::CoerceUnsized; // :coerce_unsized } pub mod prelude { -- cgit v1.2.3 From 7ebac5e54c51c6b8f1ddf3bb905f625416cc09fa Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Tue, 15 Jun 2021 21:34:26 +0300 Subject: internal: switch some tests to minicore --- crates/test_utils/src/minicore.rs | 28 +++++++++++++++++++++++++--- 1 file changed, 25 insertions(+), 3 deletions(-) (limited to 'crates/test_utils') diff --git a/crates/test_utils/src/minicore.rs b/crates/test_utils/src/minicore.rs index 8f8f1c9f8..a61459f6d 100644 --- a/crates/test_utils/src/minicore.rs +++ b/crates/test_utils/src/minicore.rs @@ -9,7 +9,9 @@ //! //! Available flags: //! sized: +//! slice: //! unsize: sized +//! deref: sized //! coerce_unsized: unsize pub mod marker { @@ -27,8 +29,8 @@ pub mod marker { } pub mod ops { + // region:coerce_unsized mod unsize { - // region:coerce_unsized use crate::marker::Unsize; #[lang = "coerce_unsized"] @@ -45,11 +47,31 @@ pub mod ops { impl, U: ?Sized> CoerceUnsized<*mut U> for *mut T {} impl, U: ?Sized> CoerceUnsized<*const U> for *mut T {} impl, U: ?Sized> CoerceUnsized<*const U> for *const T {} - // endregion:coerce_unsized } + pub use self::unsize::CoerceUnsized; + // endregion:coerce_unsized - pub use self::unsize::CoerceUnsized; // :coerce_unsized + // region:deref + mod deref { + #[lang = "deref"] + pub trait Deref { + #[lang = "deref_target"] + type Target: ?Sized; + fn deref(&self) -> &Self::Target; + } + } + pub use self::deref::Deref; + // endregion:deref +} + +// region:slice +pub mod slice { + #[lang = "slice"] + impl [T] { + pub fn len(&self) -> usize { loop {} } + } } +// endregion:slice pub mod prelude { pub mod v1 { -- cgit v1.2.3 From 0bb1f1bc90ee0f0f92f55823fc2e0c12c6acb680 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Tue, 15 Jun 2021 21:45:25 +0300 Subject: internal: add ranges to minicore --- crates/test_utils/src/minicore.rs | 42 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 41 insertions(+), 1 deletion(-) (limited to 'crates/test_utils') diff --git a/crates/test_utils/src/minicore.rs b/crates/test_utils/src/minicore.rs index a61459f6d..f9f14b7df 100644 --- a/crates/test_utils/src/minicore.rs +++ b/crates/test_utils/src/minicore.rs @@ -10,6 +10,7 @@ //! Available flags: //! sized: //! slice: +//! range: //! unsize: sized //! deref: sized //! coerce_unsized: unsize @@ -62,13 +63,52 @@ pub mod ops { } pub use self::deref::Deref; // endregion:deref + + //region:range + mod range { + #[lang = "RangeFull"] + pub struct RangeFull; + + #[lang = "Range"] + pub struct Range { + pub start: Idx, + pub end: Idx, + } + + #[lang = "RangeFrom"] + pub struct RangeFrom { + pub start: Idx, + } + + #[lang = "RangeTo"] + pub struct RangeTo { + pub end: Idx, + } + + #[lang = "RangeInclusive"] + pub struct RangeInclusive { + pub(crate) start: Idx, + pub(crate) end: Idx, + pub(crate) exhausted: bool, + } + + #[lang = "RangeToInclusive"] + pub struct RangeToInclusive { + pub end: Idx, + } + } + pub use self::range::{Range, RangeFrom, RangeFull, RangeTo}; + pub use self::range::{RangeInclusive, RangeToInclusive}; + //endregion:range } // region:slice pub mod slice { #[lang = "slice"] impl [T] { - pub fn len(&self) -> usize { loop {} } + pub fn len(&self) -> usize { + loop {} + } } } // endregion:slice -- cgit v1.2.3 From 2eef66a2ed9b02962511e38c620efb23e2d65b00 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Tue, 15 Jun 2021 22:38:21 +0300 Subject: internal: sanity-check minicore flags --- crates/test_utils/src/fixture.rs | 9 +++++++++ crates/test_utils/src/minicore.rs | 4 ++-- 2 files changed, 11 insertions(+), 2 deletions(-) (limited to 'crates/test_utils') diff --git a/crates/test_utils/src/fixture.rs b/crates/test_utils/src/fixture.rs index 535892f3f..779146084 100644 --- a/crates/test_utils/src/fixture.rs +++ b/crates/test_utils/src/fixture.rs @@ -276,6 +276,7 @@ impl MiniCore { } let mut curr_region = ""; + let mut seen_regions = Vec::new(); for line in lines { let trimmed = line.trim(); if let Some(region) = trimmed.strip_prefix("// region:") { @@ -288,6 +289,7 @@ impl MiniCore { curr_region = ""; continue; } + seen_regions.push(curr_region); let mut flag = curr_region; if let Some(idx) = trimmed.find("// :") { @@ -305,6 +307,13 @@ impl MiniCore { buf.push_str(line) } } + + for flag in &self.valid_flags { + if !seen_regions.iter().any(|it| it == flag) { + panic!("unused minicore flag: {:?}", flag); + } + } + buf } } diff --git a/crates/test_utils/src/minicore.rs b/crates/test_utils/src/minicore.rs index f9f14b7df..8c0d122dc 100644 --- a/crates/test_utils/src/minicore.rs +++ b/crates/test_utils/src/minicore.rs @@ -64,7 +64,7 @@ pub mod ops { pub use self::deref::Deref; // endregion:deref - //region:range + // region:range mod range { #[lang = "RangeFull"] pub struct RangeFull; @@ -99,7 +99,7 @@ pub mod ops { } pub use self::range::{Range, RangeFrom, RangeFull, RangeTo}; pub use self::range::{RangeInclusive, RangeToInclusive}; - //endregion:range + // endregion:range } // region:slice -- cgit v1.2.3 From 3efe5c3426a311b6d617f9718b82e9a598dfa06d Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Tue, 15 Jun 2021 22:49:00 +0300 Subject: internal: add future to minicore --- crates/test_utils/src/minicore.rs | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) (limited to 'crates/test_utils') diff --git a/crates/test_utils/src/minicore.rs b/crates/test_utils/src/minicore.rs index 8c0d122dc..127d06e59 100644 --- a/crates/test_utils/src/minicore.rs +++ b/crates/test_utils/src/minicore.rs @@ -14,6 +14,8 @@ //! unsize: sized //! deref: sized //! coerce_unsized: unsize +//! pin: +//! future: pin pub mod marker { // region:sized @@ -113,6 +115,41 @@ pub mod slice { } // endregion:slice +// region:pin +pub mod pin { + #[lang = "pin"] + #[fundamental] + pub struct Pin

{ + pointer: P, + } +} +// endregion:pin + +// region:future +pub mod future { + use crate::{pin::Pin, task::{Poll, Context}}; + + #[lang = "future_trait"] + pub trait Future { + type Output; + #[lang = "poll"] + fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll; + } +} +pub mod task { + pub enum Poll { + #[lang = "Ready"] + Ready(T), + #[lang = "Pending"] + Pending, + } + + pub struct Context<'a> { + waker: &'a (), + } +} +// endregion:future + pub mod prelude { pub mod v1 { pub use crate::marker::Sized; // :sized -- cgit v1.2.3 From 2870d2bade94ae276cba56caf8c35feaacd49422 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Tue, 15 Jun 2021 22:59:51 +0300 Subject: internal: add option to minicore --- crates/test_utils/src/fixture.rs | 2 ++ crates/test_utils/src/minicore.rs | 18 +++++++++++++++++- 2 files changed, 19 insertions(+), 1 deletion(-) (limited to 'crates/test_utils') diff --git a/crates/test_utils/src/fixture.rs b/crates/test_utils/src/fixture.rs index 779146084..6ba112de8 100644 --- a/crates/test_utils/src/fixture.rs +++ b/crates/test_utils/src/fixture.rs @@ -198,6 +198,7 @@ impl MiniCore { self.activated_flags.iter().any(|it| it == flag) } + #[track_caller] fn assert_valid_flag(&self, flag: &str) { if !self.valid_flags.iter().any(|it| it == flag) { panic!("invalid flag: {:?}, valid flags: {:?}", flag, self.valid_flags); @@ -299,6 +300,7 @@ impl MiniCore { let skip = if flag == "" { false } else { + assert!(!flag.starts_with(' '), "region marker starts with a space: {:?}", flag); self.assert_valid_flag(flag); !self.has_flag(flag) }; diff --git a/crates/test_utils/src/minicore.rs b/crates/test_utils/src/minicore.rs index 127d06e59..cb18c8796 100644 --- a/crates/test_utils/src/minicore.rs +++ b/crates/test_utils/src/minicore.rs @@ -16,6 +16,7 @@ //! coerce_unsized: unsize //! pin: //! future: pin +//! option: pub mod marker { // region:sized @@ -115,6 +116,17 @@ pub mod slice { } // endregion:slice +// region:option +pub mod option { + pub enum Option { + #[lang = "None"] + None, + #[lang = "Some"] + Some(T), + } +} +// endregion:option + // region:pin pub mod pin { #[lang = "pin"] @@ -127,7 +139,10 @@ pub mod pin { // region:future pub mod future { - use crate::{pin::Pin, task::{Poll, Context}}; + use crate::{ + pin::Pin, + task::{Context, Poll}, + }; #[lang = "future_trait"] pub trait Future { @@ -153,6 +168,7 @@ pub mod task { pub mod prelude { pub mod v1 { pub use crate::marker::Sized; // :sized + pub use crate::option::Option::{self, None, Some}; // :option } pub mod rust_2015 { -- cgit v1.2.3 From 0798cce9e564774b663fd965aaf2ef7e5778cb3f Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Tue, 15 Jun 2021 23:07:25 +0300 Subject: internal: add result to minicore --- crates/test_utils/src/minicore.rs | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) (limited to 'crates/test_utils') diff --git a/crates/test_utils/src/minicore.rs b/crates/test_utils/src/minicore.rs index cb18c8796..5ff60178c 100644 --- a/crates/test_utils/src/minicore.rs +++ b/crates/test_utils/src/minicore.rs @@ -17,6 +17,7 @@ //! pin: //! future: pin //! option: +//! result: pub mod marker { // region:sized @@ -127,6 +128,17 @@ pub mod option { } // endregion:option +// region:result +pub mod result { + pub enum Result { + #[lang = "Ok"] + Ok(T), + #[lang = "Err"] + Err(E), + } +} +// endregion:result + // region:pin pub mod pin { #[lang = "pin"] @@ -167,8 +179,11 @@ pub mod task { pub mod prelude { pub mod v1 { - pub use crate::marker::Sized; // :sized - pub use crate::option::Option::{self, None, Some}; // :option + pub use crate::{ + marker::Sized, // :sized + option::Option::{self, None, Some}, // :option + result::Result::{self, Err, Ok}, // :result + }; } pub mod rust_2015 { -- cgit v1.2.3