compiler: Resolve region indexes from checked declarations

287a66c83a052d4732fede6877de2f307bf1c91331806259bff4f52078bf7bcd
Alexis Sellier committed ago 1 parent deaafa1d
lib/std/lang/resolver.rad +23 -22
6827 6827
        set arguments[i] = nil;
6828 6828
    }
6829 6829
    return RegionSubstitution { parameters, arguments };
6830 6830
}
6831 6831
6832 -
/// Find the position of a region in a substitution's declared parameter list.
6833 -
unsafe fn regionParameter(map: &RegionSubstitution, region: *unsafe types::Region) -> ?u32 {
6834 -
    for parameter, i in map.parameters.entries {
6835 -
        if parameter.id == region.id {
6836 -
            return i;
6832 +
/// Find a region's position among the region declarations in one scope.
6833 +
fn regionIndex(scope: &RegionScope, regionId: u32) -> ?u32 {
6834 +
    match scope.declarations {
6835 +
        case RegionDeclarations::Parameters(nodes) => {
6836 +
            let mut index: u32 = 0;
6837 +
            for node in nodes {
6838 +
                let case ast::NodeValue::Region { .. } = node.value else continue;
6839 +
                if node.id == regionId {
6840 +
                    return index;
6841 +
                }
6842 +
                set index += 1;
6843 +
            }
6844 +
        }
6845 +
        case RegionDeclarations::Block(node) => {
6846 +
            if node.id == regionId {
6847 +
                return 0;
6848 +
            }
6837 6849
        }
6838 6850
    }
6839 6851
    return nil;
6840 6852
}
6841 6853
6843 6855
unsafe fn inferRegionClass 'arena (
6844 6856
    self: &mut Resolver 'arena, map: &RegionSubstitution,
6845 6857
    expected: types::PointerClass, actual: types::PointerClass, site: *ast::Node
6846 6858
) throws (ResolveError) {
6847 6859
    let case types::PointerClass::Region(parameter) = expected else return;
6848 -
    let index = regionParameter(map, parameter) else return;
6860 +
    let index = regionIndex(map.parameters, parameter.id) else return;
6849 6861
    let case types::PointerClass::Region(argument) = actual
6850 6862
        else throw emitError(self, site, ErrorKind::RegionInference(parameter.name));
6851 6863
    if let previous = map.arguments[index]; previous.id <> argument.id {
6852 6864
        throw emitError(self, site, ErrorKind::RegionInference(parameter.name));
6853 6865
    }
6935 6947
            throw emitError(self, site, ErrorKind::RegionInference(parameter.name));
6936 6948
        }
6937 6949
    }
6938 6950
    for parameter, i in map.parameters.entries {
6939 6951
        let parent = parameter.parent else continue;
6940 -
        let index = regionParameter(map, parent) else panic "validateRegionArguments: unknown parent";
6952 +
        let index = regionIndex(map.parameters, parent.id) else panic "validateRegionArguments: unknown parent";
6941 6953
        let parentArgument = map.arguments[index] else panic "validateRegionArguments: missing parent argument";
6942 6954
        let argument = map.arguments[i] else panic "validateRegionArguments: missing argument";
6943 6955
        if not types::regionContains(parentArgument, argument) {
6944 6956
            throw emitError(self, site, ErrorKind::RegionParent(parameter.name));
6945 6957
        }
6947 6959
}
6948 6960
6949 6961
/// Substitute a reference's region while preserving its ownership class.
6950 6962
unsafe fn substituteRegionClass(map: &RegionSubstitution, class: types::PointerClass) -> types::PointerClass {
6951 6963
    let case types::PointerClass::Region(region) = class else return class;
6952 -
    let index = regionParameter(map, region) else return class;
6964 +
    let index = regionIndex(map.parameters, region.id) else return class;
6953 6965
    let argument = map.arguments[index] else panic "substituteRegionClass: missing argument";
6954 6966
    return types::PointerClass::Region(argument);
6955 6967
}
6956 6968
6957 6969
/// Substitute free region arguments in a type without changing its runtime layout.
6958 6970
unsafe fn substituteRegions 'arena (self: &mut Resolver 'arena, map: &RegionSubstitution, ty: Type) -> Type {
6959 6971
    match ty {
6960 6972
        case Type::Cell { class, payload } =>
6961 6973
            return Type::Cell { class: substituteRegionClass(map, class), payload: allocType(self, substituteRegions(self, map, *payload)) },
6962 6974
        case Type::Session(region) => {
6963 -
            let index = regionParameter(map, region) else return ty;
6975 +
            let index = regionIndex(map.parameters, region.id) else return ty;
6964 6976
            let argument = map.arguments[index] else panic "substituteRegions: missing session region";
6965 6977
            return Type::Session(argument);
6966 6978
        }
6967 6979
        case Type::Pointer { class, target, mutable } => {
6968 6980
            let targetType = substituteRegions(self, map, *target);
10106 10118
10107 10119
/// Return whether a region identity is visible in a lexical environment.
10108 10120
fn regionInScope(scope: ?*RegionScope, regionId: u32) -> bool {
10109 10121
    let mut cursor = scope;
10110 10122
    while let current = cursor {
10111 -
        match current.declarations {
10112 -
            case RegionDeclarations::Parameters(nodes) => {
10113 -
                for node in nodes {
10114 -
                    if let case ast::NodeValue::Region { .. } = node.value; node.id == regionId {
10115 -
                        return true;
10116 -
                    }
10117 -
                }
10118 -
            }
10119 -
            case RegionDeclarations::Block(node) => {
10120 -
                if node.id == regionId {
10121 -
                    return true;
10122 -
                }
10123 -
            }
10123 +
        if regionIndex(current, regionId) <> nil {
10124 +
            return true;
10124 10125
        }
10125 10126
        set cursor = current.parent;
10126 10127
    }
10127 10128
    return false;
10128 10129
}
lib/std/lang/resolver/tests/regions.rad +16 -0
585 585
        let err = try super::expectError(&result);
586 586
        let case resolver::ErrorKind::BorrowConflict(_) = err.kind else throw testing::TestError::Failed;
587 587
    }
588 588
}
589 589
590 +
/// Ownership markers do not change the positions of nominal region arguments.
591 +
@test unsafe fn testNominalRegionParameterOrder() throws (testing::TestError) {
592 +
    for program in [
593 +
        "record Pair: Copy + 'a + 'b { left: &'a u32, right: &'b u32 } fn f 'x 'y (left: &'x u32, right: &'y u32) -> Pair 'x 'y { return Pair 'x 'y { left, right }; }",
594 +
        "record Pair: 'a + Copy + 'b { left: &'a u32, right: &'b u32 } fn f 'x 'y (left: &'x u32, right: &'y u32) -> Pair 'x 'y { return Pair 'x 'y { left, right }; }",
595 +
        "record Pair: 'a + 'b + Copy { left: &'a u32, right: &'b u32 } fn f 'x 'y (left: &'x u32, right: &'y u32) -> Pair 'x 'y { return Pair 'x 'y { left, right }; }",
596 +
    ] {
597 +
        let mut arena = super::testArena();
598 +
        let storage: 'test = &mut arena in {
599 +
            let mut res = super::testResolver(storage);
600 +
            let result = try super::resolveProgramStr(&mut res, program);
601 +
            try super::expectNoErrors(&result);
602 +
        }
603 +
    }
604 +
}
605 +
590 606
/// Exact arguments share one descriptor and all applications share the source layout.
591 607
@test unsafe fn testNominalRegionApplications() throws (testing::TestError) {
592 608
    let mut testArena19 = super::testArena();
593 609
    let testStorage19: 'test19 = &mut testArena19 in {
594 610
        let mut res = super::testResolver(testStorage19);