Skip to content
This repository was archived by the owner on May 23, 2024. It is now read-only.

Commit 114c9de

Browse files
authored
Merge pull request #1007 from JohnTitor/add-ices-2021-11
Add some ICEs
2 parents 73cbd50 + 414caed commit 114c9de

13 files changed

+666
-12
lines changed
File renamed without changes.

ices/88468.rs

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
#![allow(incomplete_features)]
2+
#![feature(generic_const_exprs)]
3+
#![crate_type = "lib"]
4+
5+
struct Assert<const COND: bool>;
6+
trait IsTrue {}
7+
impl IsTrue for Assert<true> {}
8+
9+
trait IsNotZst {}
10+
11+
impl<T> IsNotZst for T
12+
where
13+
Assert<{ std::mem::size_of::<T>() > 0 }>: IsTrue,
14+
{}
15+
16+
fn assert_not_zero_sized<T: IsNotZst>(_: T) {}
17+
18+
fn main() {
19+
assert_not_zero_sized(vec![1, 2, 3]);
20+
}

ices/88599.sh renamed to ices/88599.rs

+1-5
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,4 @@
1-
#!/bin/bash
2-
3-
rustc --crate-type lib - << EOF
1+
#![crate_type = "lib"]
42

53
pub trait First {
64
const CONST: bool;
@@ -18,5 +16,3 @@ pub trait Foo {
1816
impl <'a> Foo for () where &'a Self: Foo {
1917
const CONST: bool = <&Self>::CONST;
2018
}
21-
22-
EOF
+1-7
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,4 @@
1-
#!/bin/bash
2-
3-
rustc --crate-type lib - << EOF
1+
#![crate_type = "lib"]
42

53
use std::collections::HashMap;
64

@@ -13,7 +11,3 @@ pub trait WidgetExt {
1311
}
1412

1513
static CALLBACKS: HashMap<*const dyn WidgetExt, dyn FnMut(&mut _) + 'static> = HashMap::new();
16-
17-
pub fn main() {}
18-
19-
EOF

ices/89022-1.rs

+256
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,256 @@
1+
#![feature(adt_const_params)]
2+
#![feature(generic_const_exprs)]
3+
#![feature(const_fn_trait_bound)]
4+
5+
use core::marker::PhantomData;
6+
use std::collections::HashMap;
7+
8+
// const-evaluable equality for string slices
9+
pub const fn str_eq(lhs: &str, rhs: &str) -> bool {
10+
let lhs_bytes = lhs.as_bytes();
11+
let rhs_bytes = rhs.as_bytes();
12+
let mut i = 0;
13+
let bytes = if lhs_bytes.len() == rhs_bytes.len() {
14+
lhs_bytes.len()
15+
} else {
16+
return false;
17+
};
18+
19+
while i < bytes {
20+
if lhs_bytes[i] != rhs_bytes[i] {
21+
return false;
22+
}
23+
i += 1;
24+
}
25+
return true;
26+
}
27+
28+
pub trait ContainsKey<const K: &'static str> {}
29+
30+
// trait used to compare two types that have type-encoded lists of keys (in this cast static strings)
31+
pub trait KeySchema {
32+
const KEYS: &'static [&'static str];
33+
const SIZE: usize;
34+
}
35+
36+
pub struct KeyNil;
37+
impl KeySchema for KeyNil {
38+
const KEYS: &'static [&'static str] = &[];
39+
const SIZE: usize = 0;
40+
}
41+
42+
pub struct KeyCons<Tail, const KEY_ID: &'static str>
43+
where
44+
Tail: KeySchema,
45+
{
46+
_tail: PhantomData<Tail>,
47+
}
48+
49+
pub const fn compute_successor_size<T: KeySchema>() -> usize {
50+
T::SIZE + 1
51+
}
52+
53+
pub const fn construct_successor_array<Tail: KeySchema>(
54+
successor_key: &'static str,
55+
) -> [&'static str; compute_successor_size::<Tail>()]
56+
where
57+
[&'static str; compute_successor_size::<Tail>()]: Sized,
58+
{
59+
let mut keys = [""; compute_successor_size::<Tail>()];
60+
let tail_keys = Tail::KEYS;
61+
let mut i = 0;
62+
let old_array_size: usize = compute_successor_size::<Tail>() - 1;
63+
while i < old_array_size {
64+
keys[i] = tail_keys[i];
65+
i += 1;
66+
}
67+
keys[old_array_size] = successor_key;
68+
keys
69+
}
70+
71+
pub const fn is_equivalent_except<const K: &'static str>(
72+
with_k: &[&'static str],
73+
without_k: &[&'static str],
74+
) -> bool {
75+
let mut i = 0;
76+
while i < with_k.len() {
77+
if str_eq(with_k[i], K) {
78+
i += 1;
79+
continue;
80+
}
81+
let mut j = 0;
82+
let mut match_found = false;
83+
while j < without_k.len() {
84+
if str_eq(with_k[i], without_k[j]) {
85+
match_found = true;
86+
break;
87+
}
88+
j += 1;
89+
}
90+
if !match_found {
91+
return false;
92+
}
93+
i += 1;
94+
}
95+
return true;
96+
}
97+
98+
// Outputs a usize in order to make the array invalid by underflowing
99+
// Alternatively this could use const_panic to produce good error messages
100+
pub const fn check_valid_subset<S1: KeySchema, S2: KeySchema, const K: &'static str>() -> usize
101+
where
102+
S1: ContainsKey<K>,
103+
{
104+
let with_k: &[&'static str] = &S1::KEYS;
105+
let without_k: &[&'static str] = &S2::KEYS;
106+
107+
if with_k.len() <= without_k.len() {
108+
// panic because S1 isn't bigger
109+
return (with_k.len() - 1) - without_k.len(); // panic using underflow
110+
}
111+
112+
if !is_equivalent_except::<K>(with_k, without_k) {
113+
// panic because S2 doesn't have the rest of S1's elements
114+
return (without_k.len() - 1) - with_k.len(); // panic using underflow
115+
}
116+
117+
return 1;
118+
}
119+
120+
pub trait SubsetExcept<Parent: KeySchema, const K: &'static str>: KeySchema
121+
where
122+
[(); Parent::SIZE - Self::SIZE]: Sized,
123+
Parent: ContainsKey<K>,
124+
{
125+
}
126+
127+
impl<Schema, PossibleParent, const K: &'static str> SubsetExcept<PossibleParent, K> for Schema
128+
where
129+
Schema: KeySchema,
130+
PossibleParent: KeySchema,
131+
PossibleParent: ContainsKey<K>,
132+
[(); PossibleParent::SIZE - Schema::SIZE]: Sized,
133+
[(); check_valid_subset::<PossibleParent, Schema, K>()]: Sized,
134+
{
135+
}
136+
137+
impl<Tail, const KEY_ID: &'static str> KeySchema for KeyCons<Tail, KEY_ID>
138+
where
139+
Tail: KeySchema,
140+
[(); compute_successor_size::<Tail>()]: Sized,
141+
{
142+
const KEYS: &'static [&'static str] = &construct_successor_array::<Tail>(KEY_ID);
143+
const SIZE: usize = compute_successor_size::<Tail>();
144+
}
145+
146+
// thanks to matt1992#5582 on the Rust Programming Language Community Discord for offering this strategy
147+
// a const expression calls a function, which provides a "proof" that a given type should always use a given implementation
148+
pub trait ContainsKeyHelper<const IS_EQUAL: bool, const K: &'static str> {}
149+
150+
const fn contains_key_helper_helper<const KEY_ID: &'static str, const K: &'static str>() -> bool {
151+
str_eq(KEY_ID, K)
152+
}
153+
impl<Tail, const KEY_ID: &'static str, const K: &'static str> ContainsKey<K>
154+
for KeyCons<Tail, KEY_ID>
155+
where
156+
Tail: KeySchema,
157+
Self: ContainsKeyHelper<{ contains_key_helper_helper::<KEY_ID, K>() }, K>,
158+
{
159+
}
160+
161+
impl<Tail, const KEY_ID: &'static str, const K: &'static str> ContainsKeyHelper<false, K>
162+
for KeyCons<Tail, KEY_ID>
163+
where
164+
Tail: KeySchema + ContainsKey<K>,
165+
{
166+
}
167+
168+
impl<Tail, const KEY_ID: &'static str, const K: &'static str> ContainsKeyHelper<true, K>
169+
for KeyCons<Tail, KEY_ID>
170+
where
171+
Tail: KeySchema,
172+
{
173+
}
174+
175+
pub struct RestrictedStringMap<S: KeySchema> {
176+
inner: HashMap<&'static str, Option<String>>,
177+
// schemas should be 0-sized, but I use a phantom data here just to emphasize that there's no data dependency
178+
_schema: PhantomData<S>,
179+
}
180+
impl<S: KeySchema, const K: &'static str> ContainsKey<K> for RestrictedStringMap<S> where
181+
S: ContainsKey<K>
182+
{
183+
}
184+
impl<S: KeySchema> RestrictedStringMap<S>
185+
where
186+
[(); compute_successor_size::<S>()]: Sized,
187+
{
188+
pub fn empty_schema() -> RestrictedStringMap<KeyNil> {
189+
RestrictedStringMap::<_> {
190+
inner: HashMap::new(),
191+
// schemas should be 0-sized, but I use a phantom data here just to emphasize that there's no data dependency
192+
_schema: PhantomData::<_>,
193+
}
194+
}
195+
196+
pub fn new() -> Self {
197+
let mut hm: HashMap<&'static str, Option<String>> = HashMap::new();
198+
199+
for k in S::KEYS {
200+
hm.insert(*k, None);
201+
}
202+
203+
hm.shrink_to_fit();
204+
205+
Self {
206+
inner: hm,
207+
_schema: PhantomData::<_>,
208+
}
209+
}
210+
211+
/// Adds a possible &'static str to the HashMap.
212+
/// This requires consuming the map since our type must change to reflect the new schema.
213+
pub fn add_key<const K: &'static str>(self) -> RestrictedStringMap<KeyCons<S, K>>
214+
where
215+
// Proof asserting that one size larger is still a valid schema
216+
// this should only be untrue if the number of keys exceeds usize::MAX
217+
[(); compute_successor_size::<S>()]: Sized,
218+
{
219+
let Self { mut inner, .. } = self;
220+
inner.insert(K, None);
221+
RestrictedStringMap::<_> {
222+
inner: inner,
223+
_schema: PhantomData::<_>,
224+
}
225+
}
226+
227+
// I don't know of a way to remove the &'static str other than having the user provide their own new schema.
228+
// This is because I can't use a dependently typed function to construct a return type.
229+
// That's the only way I can think of to compute what the return type of such a function would look like without user input.
230+
//
231+
pub fn remove_key<NewSchema: KeySchema, const K: &'static str>(
232+
self,
233+
) -> RestrictedStringMap<NewSchema>
234+
where
235+
Self: ContainsKey<K>,
236+
S: ContainsKey<K>,
237+
NewSchema: SubsetExcept<S, K>,
238+
[(); S::SIZE - NewSchema::SIZE]: Sized,
239+
{
240+
let Self { mut inner, .. } = self;
241+
inner.remove(&K);
242+
RestrictedStringMap::<_> {
243+
inner: inner,
244+
_schema: PhantomData::<_>,
245+
}
246+
}
247+
}
248+
249+
fn foo() {
250+
let map: RestrictedStringMap<KeyNil> = RestrictedStringMap::<KeyNil>::empty_schema();
251+
let mut map: RestrictedStringMap<KeyCons<KeyCons<KeyNil, "k1">, "k2">> =
252+
map.add_key::<"k1">().add_key::<"k2">();
253+
let map: RestrictedStringMap<KeyCons<KeyNil, "k1">> = map.remove_key::<_, "k2">();
254+
}
255+
256+
fn main() {}

0 commit comments

Comments
 (0)