Skip to content

Commit c74da51

Browse files
committed
Auto merge of #616 - nathanwhit:fundamental-multiple-params, r=jackh726
Support fundamental types with multiple type parameters Closes #615.
2 parents 9325fb6 + 2ee1c9d commit c74da51

File tree

4 files changed

+100
-54
lines changed

4 files changed

+100
-54
lines changed

chalk-integration/src/lowering.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -274,7 +274,7 @@ impl LowerWithEnv for (&AdtDefn, chalk_ir::AdtId<ChalkIr>) {
274274
fn lower(&self, env: &Env) -> LowerResult<Self::Lowered> {
275275
let (adt_defn, adt_id) = self;
276276

277-
if adt_defn.flags.fundamental && adt_defn.all_parameters().len() != 1 {
277+
if adt_defn.flags.fundamental && adt_defn.all_parameters().len() < 1 {
278278
Err(RustIrError::InvalidFundamentalTypesParameters(
279279
adt_defn.name.clone(),
280280
))?;

chalk-solve/src/clauses/program_clauses.rs

Lines changed: 28 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -361,18 +361,20 @@ impl<I: Interner> ToProgramClauses<I> for AdtDatum<I> {
361361
/// ```notrust
362362
/// #[upstream]
363363
/// #[fundamental]
364-
/// struct Box<T> {}
364+
/// struct Box<T, U> {}
365365
/// ```
366366
///
367367
/// We generate the following clauses:
368368
///
369369
/// ```notrust
370-
/// forall<T> { IsLocal(Box<T>) :- IsLocal(T). }
370+
/// forall<T, U> { IsLocal(Box<T, U>) :- IsLocal(T). }
371+
/// forall<T, U> { IsLocal(Box<T, U>) :- IsLocal(U). }
371372
///
372-
/// forall<T> { IsUpstream(Box<T>) :- IsUpstream(T). }
373+
/// forall<T, U> { IsUpstream(Box<T, U>) :- IsUpstream(T), IsUpstream(U). }
373374
///
374375
/// // Generated for both upstream and local fundamental types
375-
/// forall<T> { DownstreamType(Box<T>) :- DownstreamType(T). }
376+
/// forall<T, U> { DownstreamType(Box<T, U>) :- DownstreamType(T). }
377+
/// forall<T, U> { DownstreamType(Box<T, U>) :- DownstreamType(U). }
376378
/// ```
377379
///
378380
#[instrument(level = "debug", skip(builder))]
@@ -395,38 +397,6 @@ impl<I: Interner> ToProgramClauses<I> for AdtDatum<I> {
395397
let self_appl_ty = application_ty(builder, id);
396398
let self_ty = self_appl_ty.clone().intern(interner);
397399

398-
// Fundamental types often have rules in the form of:
399-
// Goal(FundamentalType<T>) :- Goal(T)
400-
// This macro makes creating that kind of clause easy
401-
macro_rules! fundamental_rule {
402-
($goal:ident) => {
403-
// Fundamental types must always have at least one
404-
// type parameter for this rule to make any
405-
// sense. We currently do not have have any
406-
// fundamental types with more than one type
407-
// parameter, nor do we know what the behaviour
408-
// for that should be. Thus, we are asserting here
409-
// that there is only a single type parameter
410-
// until the day when someone makes a decision
411-
// about how that should behave.
412-
assert_eq!(
413-
self_appl_ty.len_type_parameters(interner),
414-
1,
415-
"Only fundamental types with a single parameter are supported"
416-
);
417-
418-
builder.push_clause(
419-
DomainGoal::$goal(self_ty.clone()),
420-
Some(DomainGoal::$goal(
421-
// This unwrap is safe because we asserted
422-
// above for the presence of a type
423-
// parameter
424-
self_appl_ty.first_type_parameter(interner).unwrap(),
425-
)),
426-
);
427-
};
428-
}
429-
430400
// Types that are not marked `#[upstream]` satisfy IsLocal(TypeName)
431401
if !self.flags.upstream {
432402
// `IsLocalTy(Ty)` depends *only* on whether the type
@@ -436,15 +406,34 @@ impl<I: Interner> ToProgramClauses<I> for AdtDatum<I> {
436406
// If a type is `#[upstream]`, but is also
437407
// `#[fundamental]`, it satisfies IsLocal if and only
438408
// if its parameters satisfy IsLocal
439-
fundamental_rule!(IsLocal);
440-
fundamental_rule!(IsUpstream);
409+
for type_param in self_appl_ty.type_parameters(interner) {
410+
builder.push_clause(
411+
DomainGoal::IsLocal(self_ty.clone()),
412+
Some(DomainGoal::IsLocal(type_param)),
413+
);
414+
}
415+
builder.push_clause(
416+
DomainGoal::IsUpstream(self_ty.clone()),
417+
self_appl_ty
418+
.type_parameters(interner)
419+
.map(|type_param| DomainGoal::IsUpstream(type_param)),
420+
);
441421
} else {
442422
// The type is just upstream and not fundamental
443423
builder.push_fact(DomainGoal::IsUpstream(self_ty.clone()));
444424
}
445425

446426
if self.flags.fundamental {
447-
fundamental_rule!(DownstreamType);
427+
assert!(
428+
self_appl_ty.len_type_parameters(interner) >= 1,
429+
"Only fundamental types with type parameters are supported"
430+
);
431+
for type_param in self_appl_ty.type_parameters(interner) {
432+
builder.push_clause(
433+
DomainGoal::DownstreamType(self_ty.clone()),
434+
Some(DomainGoal::DownstreamType(type_param)),
435+
);
436+
}
448437
}
449438
});
450439
}

tests/lowering/mod.rs

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -454,20 +454,6 @@ fn upstream_items() {
454454
}
455455
}
456456

457-
#[test]
458-
fn fundamental_multiple_type_parameters() {
459-
lowering_error! {
460-
program {
461-
#[fundamental]
462-
struct Boxes<T, U> { }
463-
}
464-
465-
error_msg {
466-
"only a single parameter supported for fundamental type `Boxes`"
467-
}
468-
}
469-
}
470-
471457
#[test]
472458
fn tuples() {
473459
lowering_success! {

tests/test/coherence.rs

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -516,3 +516,74 @@ fn orphan_check() {
516516
}
517517
}
518518
}
519+
520+
#[test]
521+
fn fundamental_type_multiple_parameters() {
522+
// Test that implementing a local trait on a fundamental
523+
// type with multiple parameters is allowed
524+
lowering_success! {
525+
program {
526+
#[upstream]
527+
#[fundamental]
528+
struct Box<T, U> { }
529+
530+
trait Local { }
531+
532+
impl<T, U> Local for Box<T, U> { }
533+
}
534+
}
535+
536+
// Test that implementing a remote trait on a fundamental
537+
// type with multiple parameters is rejected
538+
lowering_error! {
539+
program {
540+
#[upstream]
541+
#[fundamental]
542+
struct Box<T, U> { }
543+
544+
#[upstream]
545+
trait Remote { }
546+
547+
impl<T, U> Remote for Box<T, U> { }
548+
} error_msg {
549+
"impl for trait `Remote` violates the orphan rules"
550+
}
551+
}
552+
553+
// Test that implementing a remote trait on a fundamental type
554+
// with one local type parameter is allowed
555+
lowering_success! {
556+
program {
557+
#[upstream]
558+
#[fundamental]
559+
struct Box<T, U> { }
560+
561+
struct Local { }
562+
563+
#[upstream]
564+
trait Remote { }
565+
566+
impl<T> Remote for Box<T, Local> { }
567+
}
568+
}
569+
570+
// Test that implementing a remote trait on a fundamental type
571+
// with one concrete remote type parameter is rejected
572+
lowering_error! {
573+
program {
574+
#[upstream]
575+
#[fundamental]
576+
struct Box<T, U> { }
577+
578+
#[upstream]
579+
struct Up { }
580+
581+
#[upstream]
582+
trait Remote { }
583+
584+
impl<T> Remote for Box<T, Up> { }
585+
} error_msg {
586+
"impl for trait `Remote` violates the orphan rules"
587+
}
588+
}
589+
}

0 commit comments

Comments
 (0)