Repository: FHIR/sushi (ts)

Issue:
Problem w/ example: 1)Unrecognised property '@meta'   2)Inconsistency with IG
## QA Error
![image](https://user-images.githubusercontent.com/47808/80136240-4c2e3600-8556-11ea-835c-fa0d42f559b7.png)

## Input

```
Profile:        DRSAttachment
Parent:         Attachment
Id:             drs-attachment
Title:          "DRS Attachment"
Description:    "An attachment with DRS Object attributes."
// https://github.com/ga4gh/data-repository-service-schemas/blob/master/openapi/data_repository_service.swagger.yaml#L190-L304

// adds DRSObject to Attachment
* extension contains DRSObject named drs 0..1

// remove hash from Attachment definition
* hash 0..0

// Make DRSObject MS
* extension[DRSObject] MS

Extension:  DRSObject
Id: drs-object
Title: "DRS Object"
Description: "The drs object"
* extension contains
    id 1..1 MS and
    name 0..* 

// inline definition of sub-extensions
* extension[id] ^short = "An identifier unique to this `DrsObject`."
* extension[id].value[x] only string
* extension[name] ^short = "A string that can be used to name a `DrsObject`."
* extension[name].value[x] only string


Instance: DRSAttachmentExample
InstanceOf: DRSAttachment
* extension[drs-object].extension[id].valueString = "any-id"
* extension[drs-object].extension[name].valueString = "any-file-name"

```


## Output
 build/input/examples/Attachment-DRSAttachmentExample.json

```
{
  "resourceType": "Attachment",
  "id": "DRSAttachmentExample",
  "meta": {
    "profile": [
      "http://theanvil.io/fhir/anvil/StructureDefinition/drs-attachment"
    ]
  },
  "extension": [
    {
      "extension": [
        {
          "url": "id",
          "valueString": "any-id"
        },
        {
          "url": "name",
          "valueString": "any-file-name"
        }
      ],
      "url": "http://theanvil.io/fhir/anvil/StructureDefinition/drs-object"
    }
  ]
}
```
As you can see, the meta tag QA is complaining about is present.

## IG

**However**, if we navigate to the IG artifact summary, we see this.  Note that meta tag is missing.

![image](https://user-images.githubusercontent.com/47808/80137681-7f71c480-8558-11ea-9963-76773db3bc6c.png)



Pull request:
Instances of Non-Resources
Fixes #385 and #391 

This adds support for creating Instances of non-resources. Originally, it was possible to create instances of non-resources, but they would incorrectly have a `resourceType` element, and they would be incorrectly exported to JSON files. Then we realized this was wrong, so we added an error and prevented non-resources from being created at all. 

This PR removes that error message, and adds the ability to add non-resources which do not incorrectly have a `resourceType`. A non-resource must always be `#inline`, because they should only exist within an instance of a resource. If the non-resource instance is declared and is non `#inline`, a warning is logged. Besides not having a `resourceType` and having to be `#inline`, a non-resource instance can be generated in the same way as a normal resource instance.

I've added several tests, but to further test, the example in #391 gives a good test case. When you run that example on master, you should see an error like:
```
Instance DRSAttachmentExample of type Attachment is not an Instance of a Resource or Profile of a Resource. Only Instances of Resources or Profiles of Resources may be assigned to other Instances.
```
And an `Attachment-DRSAttachmentExample.json` file will incorrectly be generated. On this branch, you should only see a warning about DRSAttachmentExample being inline (which goes away if you specify `Usage: #inline`), and the DRSAttachmentExample will be correctly inlined, without any DRSAttachmentExample.json file being generated.

Patch:
diff --git a/src/errors/FixingNonResourceError.ts b/src/errors/FixingNonResourceError.ts
deleted file mode 100644
index 0cb520c..0000000
--- a/src/errors/FixingNonResourceError.ts
+++ /dev/null
@@ -1,7 +0,0 @@
-export class FixingNonResourceError extends Error {
-  constructor(public resourceType: string, public id: string) {
-    super(
-      `Instance ${id} of type ${resourceType} is not an Instance of a Resource or Profile of a Resource. Only Instances of Resources or Profiles of Resources may be assigned to other Instances.`
-    );
-  }
-}
diff --git a/src/errors/index.ts b/src/errors/index.ts
index eba507e..0f9bea9 100644
--- a/src/errors/index.ts
+++ b/src/errors/index.ts
@@ -41,5 +41,4 @@ export * from './InvalidFHIRIdError';
 export * from './ParentDeclaredAsProfileNameError';
 export * from './ParentDeclaredAsProfileIdError';
 export * from './InvalidResourceTypeError';
-export * from './FixingNonResourceError';
 export * from './InvalidExtensionParentError';
diff --git a/src/export/InstanceExporter.ts b/src/export/InstanceExporter.ts
index fd038d9..7c9f413 100644
--- a/src/export/InstanceExporter.ts
+++ b/src/export/InstanceExporter.ts
@@ -34,10 +34,10 @@ export class InstanceExporter implements Fishable {
     rules = rules.map(r => replaceReferences(r, this.tank, this.fisher));
     // Convert strings in fixedValueRules to instances
     rules = rules.filter(r => {
-      if (r.isResource) {
+      if (r.isInstance) {
         const instance: InstanceDefinition = this.fishForFHIR(r.fixedValue as string);
         if (instance != null) {
-          r.fixedValue = instance.toJSON();
+          r.fixedValue = instance;
           return true;
         } else {
           logger.error(
@@ -54,7 +54,7 @@ export class InstanceExporter implements Fishable {
     // Patient is used for the type of a.b
     const inlineResourcePaths: { path: string; instanceOf: string }[] = [];
     rules.forEach(r => {
-      if (r.isResource && r.fixedValue instanceof InstanceDefinition) {
+      if (r.isInstance && r.fixedValue instanceof InstanceDefinition) {
         inlineResourcePaths.push({
           path: r.path,
           // We only use the first element of the meta.profile array, if a need arises for a more
@@ -191,14 +191,14 @@ export class InstanceExporter implements Fishable {
     this.validateRequiredChildElements(instanceDef, elements[0], fshDefinition);
   }
 
-  fishForFHIR(item: string) {
-    let result = this.fisher.fishForFHIR(item, Type.Instance);
+  fishForFHIR(item: string): InstanceDefinition {
+    let result = this.pkg.fish(item, Type.Instance) as InstanceDefinition;
     if (result == null) {
       // If we find a FSH definition, then we can export and fish for it again
       const fshDefinition = this.tank.fish(item, Type.Instance) as Instance;
       if (fshDefinition) {
         this.exportInstance(fshDefinition);
-        result = this.fisher.fishForFHIR(item, Type.Instance);
+        result = this.pkg.fish(item, Type.Instance) as InstanceDefinition;
       }
     }
     return result;
@@ -214,12 +214,13 @@ export class InstanceExporter implements Fishable {
       return;
     }
 
+    let isResource = true;
     const json = this.fisher.fishForFHIR(
       fshDefinition.instanceOf,
       Type.Resource,
-      Type.Type,
       Type.Profile,
-      Type.Extension
+      Type.Extension,
+      Type.Type
     );
 
     if (!json) {
@@ -230,10 +231,21 @@ export class InstanceExporter implements Fishable {
       );
     }
 
+    if (json.kind !== 'resource') {
+      // If the instance is not a resource, it should be inline, since it cannot exist as a standalone instance
+      isResource = false;
+      if (fshDefinition.usage !== 'Inline') {
+        logger.warn(
+          `Instance ${fshDefinition.name} is not an instance of a resource, so it should only be used inline on other instances, and it will not be exported to a standalone file. Specify "Usage: #inline" to remove this warning.`,
+          fshDefinition.sourceInfo
+        );
+        fshDefinition.usage = 'Inline';
+      }
+    }
+
     const instanceOfStructureDefinition = StructureDefinition.fromJSON(json);
 
     let instanceDef = new InstanceDefinition();
-    instanceDef.resourceType = instanceOfStructureDefinition.type; // ResourceType is determined by the StructureDefinition of the type
     instanceDef._instanceMeta.name = fshDefinition.id; // This is name of the instance in the FSH
     if (fshDefinition.title) {
       instanceDef._instanceMeta.title = fshDefinition.title;
@@ -244,11 +256,16 @@ export class InstanceExporter implements Fishable {
     if (fshDefinition.usage) {
       instanceDef._instanceMeta.usage = fshDefinition.usage;
     }
-    instanceDef.id = fshDefinition.id;
+    if (isResource) {
+      instanceDef.resourceType = instanceOfStructureDefinition.type; // ResourceType is determined by the StructureDefinition of the type
+      instanceDef.id = fshDefinition.id;
+    } else {
+      instanceDef._instanceMeta.sdType = instanceOfStructureDefinition.type;
+    }
 
     // Add the SD we are making an instance of to meta.profile, as long as SD is not a base FHIR resource
     // If we end up adding more metadata, we should wrap this in a setMetadata function
-    if (instanceOfStructureDefinition.derivation === 'constraint') {
+    if (isResource && instanceOfStructureDefinition.derivation === 'constraint') {
       instanceDef.meta = { profile: [instanceOfStructureDefinition.url] };
     }
 
diff --git a/src/fhirtypes/ElementDefinition.ts b/src/fhirtypes/ElementDefinition.ts
index 2500f6e..b5e7886 100644
--- a/src/fhirtypes/ElementDefinition.ts
+++ b/src/fhirtypes/ElementDefinition.ts
@@ -28,10 +28,9 @@ import {
   MultipleStandardsStatusError,
   InvalidMappingError,
   InvalidFHIRIdError,
-  FixingNonResourceError,
   DuplicateSliceError
 } from '../errors';
-import { setPropertyOnDefinitionInstance, splitOnPathPeriods, isInheritedResource } from './common';
+import { setPropertyOnDefinitionInstance, splitOnPathPeriods } from './common';
 import { Fishable, Type, Metadata, logger } from '../utils';
 import { InstanceDefinition } from './InstanceDefinition';
 import { idRegex } from './primitiveTypes';
@@ -1384,22 +1383,23 @@ export class ElementDefinition {
    * @param {InstanceDefinition} value - The resource to fix
    * @param {Fishable} fisher - A fishable implementation for finding definitions and metadata
    * @throws {MismatchedTypeError} when the ElementDefinition is not of type Resource
-   * @throws {FixingNonResourceError} when the value being fixed is non-Resource
    * @returns {InstanceDefinition} the input value when it can be fixed
    */
-  checkFixResource(value: InstanceDefinition, fisher: Fishable): InstanceDefinition {
-    if (this.type?.some(t => isInheritedResource(value.resourceType, t.code, fisher))) {
+  checkFixInlineInstance(value: InstanceDefinition, fisher: Fishable): InstanceDefinition {
+    const inlineInstanceType = value.resourceType ?? value._instanceMeta.sdType;
+    const lineage = this.getTypeLineage(inlineInstanceType, fisher).map(
+      metadata => metadata.sdType
+    );
+    if (this.type?.some(t => lineage.includes(t.code))) {
       return value;
     } else {
-      const resource = fisher.fishForFHIR(value.resourceType, Type.Resource);
-      if (resource) {
-        // In this case the value is actually a resource, but not one that inherits from this.type
-        const typesString = this.type?.map(t => t.code).join(', ');
-        throw new MismatchedTypeError(value.resourceType, value.id, typesString);
-      } else {
-        // In this case the value is not actually a resource
-        throw new FixingNonResourceError(value.resourceType, value.id);
-      }
+      // In this case neither the type of the inline instance nor the type of any of its parents matches the
+      // ED.type, so we cannot fix the inline instance to this ED.
+      throw new MismatchedTypeError(
+        inlineInstanceType,
+        value.id,
+        this.type?.map(t => t.code).join(', ')
+      );
     }
   }
 
diff --git a/src/fhirtypes/InstanceDefinition.ts b/src/fhirtypes/InstanceDefinition.ts
index 4182af1..95f647d 100644
--- a/src/fhirtypes/InstanceDefinition.ts
+++ b/src/fhirtypes/InstanceDefinition.ts
@@ -49,6 +49,7 @@ type InstanceMeta = {
   title?: string;
   description?: string;
   usage?: InstanceUsage;
+  sdType?: string;
 };
 
 // eslint-disable-next-line @typescript-eslint/no-empty-interface
diff --git a/src/fhirtypes/StructureDefinition.ts b/src/fhirtypes/StructureDefinition.ts
index 5ef295b..ba13597 100644
--- a/src/fhirtypes/StructureDefinition.ts
+++ b/src/fhirtypes/StructureDefinition.ts
@@ -591,7 +591,7 @@ export class StructureDefinition {
     let fixedValue;
     // Fixed resources cannot be fixed by pattern[x]/fixed[x], so we must set fixedValue directly
     if (value instanceof InstanceDefinition) {
-      fixedValue = clone.checkFixResource(value, fisher);
+      fixedValue = clone.checkFixInlineInstance(value, fisher).toJSON();
     } else {
       // fixValue will throw if it fails, but skip the check if value is null
       if (value != null) {
diff --git a/src/fshtypes/rules/FixedValueRule.ts b/src/fshtypes/rules/FixedValueRule.ts
index 9b34d1d..fe1619c 100644
--- a/src/fshtypes/rules/FixedValueRule.ts
+++ b/src/fshtypes/rules/FixedValueRule.ts
@@ -16,7 +16,7 @@ export class FixedValueRule extends Rule {
   fixedValue: FixedValueType;
   exactly: boolean;
   units: boolean;
-  isResource: boolean;
+  isInstance: boolean;
 
   constructor(path: string) {
     super(path);
diff --git a/src/import/FSHImporter.ts b/src/import/FSHImporter.ts
index 77c6a97..d800269 100644
--- a/src/import/FSHImporter.ts
+++ b/src/import/FSHImporter.ts
@@ -824,7 +824,7 @@ export class FSHImporter extends FSHVisitor {
       return [this.visitValueSetRule(ctx.valueSetRule())];
     } else if (ctx.fixedValueRule()) {
       const rule = this.visitFixedValueRule(ctx.fixedValueRule());
-      if (rule.isResource) {
+      if (rule.isInstance) {
         const sourceInfo = { location: this.extractStartStop(ctx), file: this.currentFile };
         logger.error(
           'Resources cannot be added inline to a Profile or Extension, skipping rule.',
@@ -987,7 +987,7 @@ export class FSHImporter extends FSHVisitor {
     fixedValueRule.fixedValue = this.visitValue(ctx.value());
     fixedValueRule.exactly = ctx.KW_EXACTLY() != null;
     fixedValueRule.units = ctx.KW_UNITS() != null;
-    fixedValueRule.isResource =
+    fixedValueRule.isInstance =
       ctx.value().SEQUENCE() != null && !this.allAliases.has(ctx.value().SEQUENCE().getText());
     return fixedValueRule;
   }


Test patch:
diff --git a/test/export/InstanceExporter.test.ts b/test/export/InstanceExporter.test.ts
index bdb8e6c..09acdf7 100644
--- a/test/export/InstanceExporter.test.ts
+++ b/test/export/InstanceExporter.test.ts
@@ -1628,7 +1628,7 @@ describe('InstanceExporter', () => {
       bundleInstance.instanceOf = 'Bundle';
       const inlineRule = new FixedValueRule('entry[0].resource');
       inlineRule.fixedValue = 'MyBundledPatient';
-      inlineRule.isResource = true;
+      inlineRule.isInstance = true;
       bundleInstance.rules.push(inlineRule); // * entry[0].resource = MyBundledPatient
       doc.instances.set(bundleInstance.name, bundleInstance);
 
@@ -1703,7 +1703,7 @@ describe('InstanceExporter', () => {
       it('should fix an inline resource to an instance', () => {
         const inlineRule = new FixedValueRule('contained[0]');
         inlineRule.fixedValue = 'MyInlinePatient';
-        inlineRule.isResource = true;
+        inlineRule.isInstance = true;
         patientInstance.rules.push(inlineRule); // * contained[0] = MyInlinePatient
 
         const exported = exportInstance(patientInstance);
@@ -1715,12 +1715,12 @@ describe('InstanceExporter', () => {
       it('should fix multiple inline resources to an instance', () => {
         const inlineRule = new FixedValueRule('contained[0]');
         inlineRule.fixedValue = 'MyInlinePatient';
-        inlineRule.isResource = true;
+        inlineRule.isInstance = true;
         patientInstance.rules.push(inlineRule); // * contained[0] = MyInlinePatient
 
         const inlineRule2 = new FixedValueRule('contained[1]');
         inlineRule2.fixedValue = 'MyInlineObservation';
-        inlineRule2.isResource = true;
+        inlineRule2.isInstance = true;
         patientInstance.rules.push(inlineRule2); // * contained[1] = MyInlineObservation
 
         const exported = exportInstance(patientInstance);
@@ -1737,7 +1737,7 @@ describe('InstanceExporter', () => {
       it('should fix an inline resource to an instance element with a specific type', () => {
         const bundleValRule = new FixedValueRule('entry[PatientsOnly].resource');
         bundleValRule.fixedValue = 'MyInlinePatient';
-        bundleValRule.isResource = true;
+        bundleValRule.isInstance = true;
         // * entry[PatientsOnly].resource = MyInlinePatient
         bundleInstance.rules.push(bundleValRule);
 
@@ -1750,7 +1750,7 @@ describe('InstanceExporter', () => {
       it('should fix an inline resource to an instance element with a choice type', () => {
         const bundleValRule = new FixedValueRule('entry[PatientOrOrganization].resource');
         bundleValRule.fixedValue = 'MyInlinePatient';
-        bundleValRule.isResource = true;
+        bundleValRule.isInstance = true;
         // * entry[PatientOrOrganization].resource = MyInlinePatient
         bundleInstance.rules.push(bundleValRule);
 
@@ -1767,7 +1767,7 @@ describe('InstanceExporter', () => {
           .withFile('BadChoice.fsh')
           .withLocation([1, 2, 3, 4]);
         bundleValRule.fixedValue = 'MyInlineObservation';
-        bundleValRule.isResource = true;
+        bundleValRule.isInstance = true;
         // * entry[PatientOrOrganization].resource = MyInlineObservation
         bundleInstance.rules.push(bundleValRule);
 
@@ -1789,7 +1789,7 @@ describe('InstanceExporter', () => {
           .withFile('FakeInstance.fsh')
           .withLocation([1, 2, 3, 4]);
         inlineRule.fixedValue = 'MyFakePatient';
-        inlineRule.isResource = true;
+        inlineRule.isInstance = true;
         patientInstance.rules.push(inlineRule); // * contained[0] = MyFakePatient
 
         const exported = exportInstance(patientInstance);
@@ -1802,7 +1802,7 @@ describe('InstanceExporter', () => {
       it('should override a fixed inline resource on an instance', () => {
         const inlineRule = new FixedValueRule('contained[0]');
         inlineRule.fixedValue = 'MyInlinePatient';
-        inlineRule.isResource = true;
+        inlineRule.isInstance = true;
         const overrideRule = new FixedValueRule('contained[0].birthDate');
         overrideRule.fixedValue = '2000-02-24';
         // * contained[0] = MyInlinePatient
@@ -1829,7 +1829,7 @@ describe('InstanceExporter', () => {
       it('should override a fixed inline resource on an instance with paths that mix usage of [0] indexing', () => {
         const inlineRule = new FixedValueRule('contained[00]'); // [00] index used
         inlineRule.fixedValue = 'MyInlinePatient';
-        inlineRule.isResource = true;
+        inlineRule.isInstance = true;
         const overrideRule = new FixedValueRule('contained.birthDate'); // no [0] index used
         overrideRule.fixedValue = '2000-02-24';
         // * contained[0] = MyInlinePatient
@@ -1858,7 +1858,7 @@ describe('InstanceExporter', () => {
         bundleRule.fixedValue = 'Bundle';
         const patientRule = new FixedValueRule('contained[0].entry[0].resource');
         patientRule.fixedValue = 'MyInlinePatient';
-        patientRule.isResource = true;
+        patientRule.isInstance = true;
         const birthDateRule = new FixedValueRule('contained[0].entry[0].resource.birthDate');
         birthDateRule.fixedValue = '2000-02-24';
         // * contained[0].resourceType = "Bundle"
@@ -1890,7 +1890,7 @@ describe('InstanceExporter', () => {
 
         const bundleRule = new FixedValueRule('contained[0]');
         bundleRule.fixedValue = 'MyBundle';
-        bundleRule.isResource = true;
+        bundleRule.isInstance = true;
         const birthDateRule = new FixedValueRule(
           'contained[0].entry[PatientsOnly].resource.birthDate'
         );
@@ -1914,6 +1914,149 @@ describe('InstanceExporter', () => {
           }
         ]);
       });
+
+      it('should fix an inline instance of a type to an instance', () => {
+        const inlineCodeable = new Instance('MyCodeable');
+        inlineCodeable.instanceOf = 'CodeableConcept';
+        inlineCodeable.usage = 'Inline';
+        doc.instances.set(inlineCodeable.name, inlineCodeable);
+        const codingRule = new FixedValueRule('coding');
+        codingRule.fixedValue = new FshCode('foo', 'http://bar.com');
+        // * coding = http://bar.com#foo
+        inlineCodeable.rules.push(codingRule);
+
+        const inlineRule = new FixedValueRule('maritalStatus');
+        inlineRule.fixedValue = 'MyCodeable';
+        inlineRule.isInstance = true;
+        // * maritalStatus = MyCodeable
+        patientInstance.rules.push(inlineRule);
+        const exported = exportInstance(patientInstance);
+        expect(exported.maritalStatus).toEqual({
+          coding: [
+            {
+              system: 'http://bar.com',
+              code: 'foo'
+            }
+          ]
+        });
+      });
+
+      it('should fix an inline instance of a specialization of a type to an instance', () => {
+        const inlineAge = new Instance('MyAge');
+        inlineAge.instanceOf = 'Age';
+        inlineAge.usage = 'Inline';
+        doc.instances.set(inlineAge.name, inlineAge);
+        const ageRule = new FixedValueRule('value');
+        ageRule.fixedValue = 42;
+        // * value = 42
+        inlineAge.rules.push(ageRule);
+
+        const inlineRule = new FixedValueRule('valueQuantity');
+        inlineRule.fixedValue = 'MyAge';
+        inlineRule.isInstance = true;
+        // * valueQuantity = MyAge
+        respRateInstance.rules.push(inlineRule);
+        const exported = exportInstance(respRateInstance);
+        expect(exported.valueQuantity).toEqual({
+          value: 42
+        });
+      });
+
+      it('should fix an inline instance of a profile of a type to an instance', () => {
+        const inlineSimple = new Instance('MySimple');
+        inlineSimple.instanceOf = 'SimpleQuantity';
+        inlineSimple.usage = 'Inline';
+        doc.instances.set(inlineSimple.name, inlineSimple);
+        const quantRule = new FixedValueRule('value');
+        quantRule.fixedValue = 7;
+        // * value = 7
+        inlineSimple.rules.push(quantRule);
+
+        const inlineRule = new FixedValueRule('valueQuantity');
+        inlineRule.fixedValue = 'MySimple';
+        inlineRule.isInstance = true;
+        // * valueQuantity = MySimple
+        respRateInstance.rules.push(inlineRule);
+        const exported = exportInstance(respRateInstance);
+        expect(exported.valueQuantity).toEqual({
+          value: 7
+        });
+      });
+
+      it('should fix an inline instance of a FSH defined profile of a type to an instance', () => {
+        const profile = new Profile('Foo');
+        profile.parent = 'Quantity';
+        doc.profiles.set(profile.name, profile);
+
+        const inlineSimple = new Instance('MyQuantity');
+        inlineSimple.instanceOf = 'Foo';
+        inlineSimple.usage = 'Inline';
+        doc.instances.set(inlineSimple.name, inlineSimple);
+        const quantRule = new FixedValueRule('value');
+        quantRule.fixedValue = 7;
+        // * value = 7
+        inlineSimple.rules.push(quantRule);
+
+        const inlineRule = new FixedValueRule('valueQuantity');
+        inlineRule.fixedValue = 'MyQuantity';
+        inlineRule.isInstance = true;
+        // * valueQuantity = MyQuantity
+        respRateInstance.rules.push(inlineRule);
+        const exported = exportInstance(respRateInstance);
+        expect(exported.valueQuantity).toEqual({
+          value: 7
+        });
+      });
+
+      it('should fix an inline instance of an extension to an instance', () => {
+        patientProfInstance.usage = 'Inline';
+        const codingRule = new FixedValueRule('extension[level].valueCoding');
+        codingRule.fixedValue = new FshCode('foo', 'http://bar.com');
+        // * extension[level].valueCoding = http://bar.com#foo
+        patientProfInstance.rules.push(codingRule);
+        const inlineRule = new FixedValueRule('extension');
+        inlineRule.fixedValue = 'Baz'; // InstanceOf patientProf defined in beforeEach
+        inlineRule.isInstance = true;
+        patientInstance.rules.push(inlineRule);
+        const exported = exportInstance(patientInstance);
+        expect(exported.extension).toEqual([
+          {
+            extension: [{ url: 'level', valueCoding: { system: 'http://bar.com', code: 'foo' } }],
+            url: 'http://hl7.org/fhir/StructureDefinition/patient-proficiency'
+          }
+        ]);
+      });
+
+      it('should fix an instance of a type to an instance and log a warning when the type is not inline', () => {
+        const inlineCodeable = new Instance('MyCodeable')
+          .withFile('Code.fsh')
+          .withLocation([1, 2, 3, 4]);
+        inlineCodeable.instanceOf = 'CodeableConcept';
+        doc.instances.set(inlineCodeable.name, inlineCodeable);
+        const codingRule = new FixedValueRule('coding');
+        codingRule.fixedValue = new FshCode('foo', 'http://bar.com');
+        // * coding = http://bar.com#foo
+        inlineCodeable.rules.push(codingRule);
+
+        const inlineRule = new FixedValueRule('maritalStatus');
+        inlineRule.fixedValue = 'MyCodeable';
+        inlineRule.isInstance = true;
+        // * maritalStatus = MyCodeable
+        patientInstance.rules.push(inlineRule);
+        const exported = exportInstance(patientInstance);
+        expect(loggerSpy.getAllMessages('warn')).toHaveLength(1);
+        expect(loggerSpy.getLastMessage('warn')).toMatch(
+          /Instance MyCodeable is not an instance of a resource.*File: Code\.fsh.*Line: 1 - 3\D*/s
+        );
+        expect(exported.maritalStatus).toEqual({
+          coding: [
+            {
+              system: 'http://bar.com',
+              code: 'foo'
+            }
+          ]
+        });
+      });
     });
   });
 
diff --git a/test/fhirtypes/ElementDefinition.checkFixResource.test.ts b/test/fhirtypes/ElementDefinition.checkFixInlineInstance.test.ts
similarity index 71%
rename from test/fhirtypes/ElementDefinition.checkFixResource.test.ts
rename to test/fhirtypes/ElementDefinition.checkFixInlineInstance.test.ts
index cb27ccf..4ef5545 100644
--- a/test/fhirtypes/ElementDefinition.checkFixResource.test.ts
+++ b/test/fhirtypes/ElementDefinition.checkFixInlineInstance.test.ts
@@ -26,35 +26,28 @@ describe('ElementDefinition', () => {
     inlineInstance = new InstanceDefinition();
     inlineInstance.resourceType = 'Patient';
     inlineInstance.id = 'MyInlineInstance';
+    inlineInstance._instanceMeta.sdType = 'Patient';
 
     inlineCodeable = new InstanceDefinition();
     inlineCodeable.resourceType = 'CodeableConcept';
     inlineCodeable.id = 'MyCodeable';
+    inlineCodeable._instanceMeta.sdType = 'CodeableConcept';
   });
 
-  describe('#checkFixResource', () => {
+  describe('#checkFixInlineInstance', () => {
     it('should return a resource when it can be fixed', () => {
       const contained = observation.elements.find(e => e.id === 'Observation.contained');
-      const value = contained.checkFixResource(inlineInstance, fisher);
+      const value = contained.checkFixInlineInstance(inlineInstance, fisher);
       expect(value.resourceType).toBe('Patient');
     });
 
     it('should throw MismatchedTypeError when a Resource is fixed on a non-Resource element', () => {
       const status = observation.elements.find(e => e.id === 'Observation.status');
       expect(() => {
-        status.checkFixResource(inlineInstance, fisher);
+        status.checkFixInlineInstance(inlineInstance, fisher);
       }).toThrow(
         'Cannot fix Patient value: MyInlineInstance. Value does not match element type: code'
       );
     });
-
-    it('should throw FixingNonResourceError when a non-Resource value is fixed on a non-Resource', () => {
-      const category = observation.elements.find(e => e.id === 'Observation.category');
-      expect(() => {
-        category.checkFixResource(inlineCodeable, fisher);
-      }).toThrow(
-        'Instance MyCodeable of type CodeableConcept is not an Instance of a Resource or Profile of a Resource. Only Instances of Resources or Profiles of Resources may be assigned to other Instances.'
-      );
-    });
   });
 });
diff --git a/test/fhirtypes/StructureDefinition.test.ts b/test/fhirtypes/StructureDefinition.test.ts
index ab061bd..72745b9 100644
--- a/test/fhirtypes/StructureDefinition.test.ts
+++ b/test/fhirtypes/StructureDefinition.test.ts
@@ -1326,15 +1326,75 @@ describe('StructureDefinition', () => {
         ).toThrow(/Bundle.*OfJoy.*Patient, Observation/);
       });
 
-      it('should not allow fixing a CodeableConcept type InstanceDefinition to any element', () => {
+      it('should allow fixing a CodeableConcept type InstanceDefinition to a CodeableConcept element', () => {
         const instanceDef = new InstanceDefinition();
-        instanceDef.id = 'CODES';
-        instanceDef.resourceType = 'CodeableConcept';
-        expect(() => respRate.validateValueAtPath('contained[0]', instanceDef, fisher)).toThrow(
-          /CODES.*CodeableConcept is not an Instance of a Resource/
+        instanceDef.coding = [{ value: '#5' }];
+        instanceDef._instanceMeta.sdType = 'CodeableConcept';
+        const { fixedValue } = respRate.validateValueAtPath('code', instanceDef, fisher);
+        expect(fixedValue).toEqual({ coding: [{ value: '#5' }] });
+      });
+
+      it('should allow fixing a specialization of a type to a type', () => {
+        const instanceDef = new InstanceDefinition();
+        instanceDef.value = 5;
+        instanceDef._instanceMeta.sdType = 'Age';
+        const { fixedValue } = respRate.validateValueAtPath('valueQuantity', instanceDef, fisher);
+        expect(fixedValue).toEqual({ value: 5 });
+      });
+
+      it('should allow fixing a profile of a type to a type', () => {
+        const instanceDef = new InstanceDefinition();
+        instanceDef.value = 5;
+        instanceDef._instanceMeta.sdType = 'SimpleQuantity';
+        const { fixedValue } = respRate.validateValueAtPath('valueQuantity', instanceDef, fisher);
+        expect(fixedValue).toEqual({ value: 5 });
+      });
+
+      it('should allow fixing a type to a choice type element', () => {
+        const instanceDef = new InstanceDefinition();
+        instanceDef.value = 5;
+        instanceDef._instanceMeta.sdType = 'Quantity';
+        const { fixedValue } = observation.validateValueAtPath('value[x]', instanceDef, fisher);
+        expect(fixedValue).toEqual({ value: 5 });
+      });
+
+      it('should not allow fixing a type that is not in the choice to a choice type element', () => {
+        const instanceDef = new InstanceDefinition();
+        instanceDef.value = 5.0;
+        instanceDef._instanceMeta.sdType = 'Money';
+        instanceDef.id = 'Cash';
+        expect(() => observation.validateValueAtPath('value[x]', instanceDef, fisher)).toThrow(
+          'Cannot fix Money value: Cash. Value does not match element type: '
         );
       });
 
+      it('should not allow fixing a type to a non-matching type', () => {
+        const instanceDef = new InstanceDefinition();
+        instanceDef.value = 5;
+        instanceDef._instanceMeta.sdType = 'Quantity';
+        instanceDef.id = 'Foo';
+        expect(() => respRate.validateValueAtPath('code', instanceDef, fisher)).toThrow(
+          'Cannot fix Quantity value: Foo. Value does not match element type: CodeableConcept'
+        );
+      });
+
+      it('should not allow fixing a parent of a type to a type', () => {
+        const instanceDef = new InstanceDefinition();
+        instanceDef._instanceMeta.sdType = 'Element';
+        instanceDef.id = 'Foo';
+        expect(() => respRate.validateValueAtPath('code', instanceDef, fisher)).toThrow(
+          'Cannot fix Element value: Foo. Value does not match element type: CodeableConcept'
+        );
+      });
+
+      it('should allow fixing an extension of to an extension element', () => {
+        const instanceDef = new InstanceDefinition();
+        instanceDef.valueString = 'hello';
+        instanceDef._instanceMeta.sdType = 'Extension';
+        const { fixedValue } = respRate.validateValueAtPath('extension', instanceDef, fisher);
+        expect(fixedValue).toEqual({ valueString: 'hello' });
+      });
+
       // Overriding elements
       it('should allow replacing parts of a Resource element', () => {
         const language = new FshCode('French');
diff --git a/test/fshtypes/rules/FixedValueRule.test.ts b/test/fshtypes/rules/FixedValueRule.test.ts
index 8b5392c..7db49e3 100644
--- a/test/fshtypes/rules/FixedValueRule.test.ts
+++ b/test/fshtypes/rules/FixedValueRule.test.ts
@@ -9,7 +9,7 @@ describe('FixedValueRule', () => {
       expect(c.fixedValue).toBeUndefined();
       expect(c.exactly).toBeUndefined();
       expect(c.units).toBeUndefined();
-      expect(c.isResource).toBeUndefined();
+      expect(c.isInstance).toBeUndefined();
     });
   });
 });
diff --git a/test/testhelpers/asserts.ts b/test/testhelpers/asserts.ts
index 7c7eb4f..c249cdb 100644
--- a/test/testhelpers/asserts.ts
+++ b/test/testhelpers/asserts.ts
@@ -71,7 +71,7 @@ export function assertFixedValueRule(
   value: FixedValueType,
   exactly = false,
   units = false,
-  isResource = false
+  isInstance = false
 ): void {
   expect(rule).toBeInstanceOf(FixedValueRule);
   const fixedValueRule = rule as FixedValueRule;
@@ -79,7 +79,7 @@ export function assertFixedValueRule(
   expect(fixedValueRule.fixedValue).toEqual(value);
   expect(fixedValueRule.exactly).toBe(exactly);
   expect(fixedValueRule.units).toBe(units);
-  expect(fixedValueRule.isResource).toEqual(isResource);
+  expect(fixedValueRule.isInstance).toEqual(isInstance);
 }
 
 export function assertOnlyRule(rule: Rule, path: string, ...types: OnlyRuleType[]): void {
diff --git a/test/testhelpers/testdefs/package/StructureDefinition-Money.json b/test/testhelpers/testdefs/package/StructureDefinition-Money.json
new file mode 100644
index 0000000..88ea77f
--- /dev/null
+++ b/test/testhelpers/testdefs/package/StructureDefinition-Money.json
@@ -0,0 +1,1 @@
+{"resourceType":"StructureDefinition","id":"Money","meta":{"lastUpdated":"2019-11-01T09:29:23.356+11:00"},"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/structuredefinition-standards-status","valueCode":"normative"},{"url":"http://hl7.org/fhir/StructureDefinition/structuredefinition-normative-version","valueCode":"4.0.0"}],"url":"http://hl7.org/fhir/StructureDefinition/Money","version":"4.0.1","name":"Money","status":"active","date":"2019-11-01T09:29:23+11:00","publisher":"HL7 FHIR Standard","contact":[{"telecom":[{"system":"url","value":"http://hl7.org/fhir"}]}],"description":"Base StructureDefinition for Money Type: An amount of economic utility in some recognized currency.","fhirVersion":"4.0.1","mapping":[{"identity":"rim","uri":"http://hl7.org/v3","name":"RIM Mapping"},{"identity":"v2","uri":"http://hl7.org/v2","name":"HL7 v2 Mapping"}],"kind":"complex-type","abstract":false,"type":"Money","baseDefinition":"http://hl7.org/fhir/StructureDefinition/Element","derivation":"specialization","snapshot":{"element":[{"id":"Money","extension":[{"url":"http://hl7.org/fhir/StructureDefinition/structuredefinition-standards-status","valueCode":"normative"},{"url":"http://hl7.org/fhir/StructureDefinition/structuredefinition-normative-version","valueCode":"4.0.0"}],"path":"Money","short":"An amount of economic utility in some recognized currency","definition":"An amount of economic utility in some recognized currency.","min":0,"max":"*","base":{"path":"Money","min":0,"max":"*"},"condition":["ele-1"],"constraint":[{"key":"ele-1","severity":"error","human":"All FHIR elements must have a @value or children","expression":"hasValue() or (children().count() > id.count())","xpath":"@value|f:*|h:div","source":"http://hl7.org/fhir/StructureDefinition/Element"}],"isModifier":false,"mapping":[{"identity":"rim","map":"n/a"},{"identity":"rim","map":"MO"}]},{"id":"Money.id","path":"Money.id","representation":["xmlAttr"],"short":"Unique id for inter-element referencing","definition":"Unique id for the element within a resource (for internal references). This may be any string value that does not contain spaces.","min":0,"max":"1","base":{"path":"Element.id","min":0,"max":"1"},"type":[{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/structuredefinition-fhir-type","valueUrl":"string"}],"code":"http://hl7.org/fhirpath/System.String"}],"isModifier":false,"isSummary":false,"mapping":[{"identity":"rim","map":"n/a"}]},{"id":"Money.extension","path":"Money.extension","slicing":{"discriminator":[{"type":"value","path":"url"}],"description":"Extensions are always sliced by (at least) url","rules":"open"},"short":"Additional content defined by implementations","definition":"May be used to represent additional information that is not part of the basic definition of the element. To make the use of extensions safe and manageable, there is a strict set of governance  applied to the definition and use of extensions. Though any implementer can define an extension, there is a set of requirements that SHALL be met as part of the definition of the extension.","comment":"There can be no stigma associated with the use of extensions by any application, project, or standard - regardless of the institution or jurisdiction that uses or defines the extensions.  The use of extensions is what allows the FHIR specification to retain a core level of simplicity for everyone.","alias":["extensions","user content"],"min":0,"max":"*","base":{"path":"Element.extension","min":0,"max":"*"},"type":[{"code":"Extension"}],"constraint":[{"key":"ele-1","severity":"error","human":"All FHIR elements must have a @value or children","expression":"hasValue() or (children().count() > id.count())","xpath":"@value|f:*|h:div","source":"http://hl7.org/fhir/StructureDefinition/Element"},{"key":"ext-1","severity":"error","human":"Must have either extensions or value[x], not both","expression":"extension.exists() != value.exists()","xpath":"exists(f:extension)!=exists(f:*[starts-with(local-name(.), \"value\")])","source":"http://hl7.org/fhir/StructureDefinition/Extension"}],"isModifier":false,"isSummary":false,"mapping":[{"identity":"rim","map":"n/a"}]},{"id":"Money.value","path":"Money.value","short":"Numerical value (with implicit precision)","definition":"Numerical value (with implicit precision).","comment":"Monetary values have their own rules for handling precision (refer to standard accounting text books).","requirements":"The amount of the currency. The value includes an implicit precision in the presentation of the value.","min":0,"max":"1","base":{"path":"Money.value","min":0,"max":"1"},"type":[{"code":"decimal"}],"constraint":[{"key":"ele-1","severity":"error","human":"All FHIR elements must have a @value or children","expression":"hasValue() or (children().count() > id.count())","xpath":"@value|f:*|h:div","source":"http://hl7.org/fhir/StructureDefinition/Element"}],"isModifier":false,"isSummary":true,"mapping":[{"identity":"v2","map":"MO.Value"}]},{"id":"Money.currency","path":"Money.currency","short":"ISO 4217 Currency Code","definition":"ISO 4217 Currency Code.","requirements":"A code indicating the currency, taken from ISO 4217.","min":0,"max":"1","base":{"path":"Money.currency","min":0,"max":"1"},"type":[{"code":"code"}],"constraint":[{"key":"ele-1","severity":"error","human":"All FHIR elements must have a @value or children","expression":"hasValue() or (children().count() > id.count())","xpath":"@value|f:*|h:div","source":"http://hl7.org/fhir/StructureDefinition/Element"}],"isModifier":false,"isSummary":true,"binding":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/elementdefinition-bindingName","valueString":"CurrencyCode"},{"url":"http://hl7.org/fhir/StructureDefinition/elementdefinition-isCommonBinding","valueBoolean":true}],"strength":"required","description":"A code indicating the currency, taken from ISO 4217.","valueSet":"http://hl7.org/fhir/ValueSet/currencies|4.0.1"},"mapping":[{"identity":"v2","map":"MO.Currency"}]}]},"differential":{"element":[{"id":"Money","extension":[{"url":"http://hl7.org/fhir/StructureDefinition/structuredefinition-standards-status","valueCode":"normative"},{"url":"http://hl7.org/fhir/StructureDefinition/structuredefinition-normative-version","valueCode":"4.0.0"}],"path":"Money","short":"An amount of economic utility in some recognized currency","definition":"An amount of economic utility in some recognized currency.","min":0,"max":"*","mapping":[{"identity":"rim","map":"MO"}]},{"id":"Money.value","path":"Money.value","short":"Numerical value (with implicit precision)","definition":"Numerical value (with implicit precision).","comment":"Monetary values have their own rules for handling precision (refer to standard accounting text books).","requirements":"The amount of the currency. The value includes an implicit precision in the presentation of the value.","min":0,"max":"1","type":[{"code":"decimal"}],"isSummary":true,"mapping":[{"identity":"v2","map":"MO.Value"}]},{"id":"Money.currency","path":"Money.currency","short":"ISO 4217 Currency Code","definition":"ISO 4217 Currency Code.","requirements":"A code indicating the currency, taken from ISO 4217.","min":0,"max":"1","type":[{"code":"code"}],"isSummary":true,"binding":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/elementdefinition-bindingName","valueString":"CurrencyCode"},{"url":"http://hl7.org/fhir/StructureDefinition/elementdefinition-isCommonBinding","valueBoolean":true}],"strength":"required","description":"A code indicating the currency, taken from ISO 4217.","valueSet":"http://hl7.org/fhir/ValueSet/currencies|4.0.1"},"mapping":[{"identity":"v2","map":"MO.Currency"}]}]}}
\ No newline at end of file